2022-01-05 21:16:17 +00:00
|
|
|
using System;
|
|
|
|
using System.Text;
|
|
|
|
using System.Text.Json;
|
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
namespace __NAMESPACE__;
|
|
|
|
|
|
|
|
public class JRpcServer<TContext>
|
|
|
|
{
|
|
|
|
public IDictionary<string, JRpcService<TContext>> Services;
|
|
|
|
|
|
|
|
public JRpcServer()
|
|
|
|
{
|
|
|
|
this.Services = new Dictionary<string, JRpcService<TContext>>();
|
|
|
|
}
|
|
|
|
|
2022-01-07 22:10:24 +00:00
|
|
|
public void AddService(JRpcService<TContext> service)
|
2022-01-05 21:16:17 +00:00
|
|
|
{
|
2022-01-07 22:10:24 +00:00
|
|
|
this.Services.Add(service.Name, service);
|
2022-01-05 21:16:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public JRpcServerSession<TContext> GetSession(JRpcTransport transport, TContext context)
|
|
|
|
{
|
|
|
|
return new JRpcServerSession<TContext>(this, transport, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class JRpcServerSession<TContext>
|
|
|
|
{
|
2022-01-11 08:44:05 +00:00
|
|
|
public JRpcServer<TContext> Server { get; private set; }
|
|
|
|
public JRpcTransport Transport { get; private set; }
|
|
|
|
public TContext Context { get; private set; }
|
2022-01-05 21:16:17 +00:00
|
|
|
|
|
|
|
public JRpcServerSession(JRpcServer<TContext> server, JRpcTransport transport, TContext context)
|
|
|
|
{
|
|
|
|
this.Server = server;
|
|
|
|
this.Transport = transport;
|
|
|
|
this.Context = context;
|
|
|
|
|
|
|
|
this.Transport.OnPacket += this.HandlePacket;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void HandlePacket(string packet)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
var parsed = JsonNode.Parse(packet);
|
|
|
|
if (parsed == null || (string?)parsed["jsonrpc"] != "2.0")
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (parsed["method"] != null) // Request or Notification
|
|
|
|
{
|
|
|
|
var id = (string?)parsed["id"];
|
|
|
|
var splitted = ((string)parsed["method"]!).Split(".", 2);
|
|
|
|
var serviceName = splitted[0];
|
|
|
|
var functionName = splitted[1];
|
|
|
|
|
|
|
|
if (serviceName == null || functionName == null)
|
|
|
|
{
|
|
|
|
if (id != null)
|
|
|
|
{
|
|
|
|
var response = new JsonObject
|
|
|
|
{
|
|
|
|
["jsonrpc"] = "2.0",
|
|
|
|
["id"] = id,
|
|
|
|
["error"] = new JsonObject
|
|
|
|
{
|
|
|
|
["code"] = -32700,
|
|
|
|
["message"] = "Method not found!",
|
|
|
|
}
|
|
|
|
};
|
|
|
|
_ = this.Transport.Write(response.ToJsonString()!);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var service = this.Server.Services[serviceName];
|
|
|
|
if (service == null)
|
|
|
|
{
|
|
|
|
if (id != null)
|
|
|
|
{
|
|
|
|
var response = new JsonObject
|
|
|
|
{
|
|
|
|
["jsonrpc"] = "2.0",
|
|
|
|
["id"] = id,
|
|
|
|
["error"] = new JsonObject
|
|
|
|
{
|
|
|
|
["code"] = -32700,
|
|
|
|
["message"] = "Method not found!",
|
|
|
|
}
|
|
|
|
};
|
|
|
|
_ = this.Transport.Write(response.ToJsonString()!);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!service.Functions.Contains(functionName))
|
|
|
|
{
|
|
|
|
if (id != null)
|
|
|
|
{
|
|
|
|
var response = new JsonObject
|
|
|
|
{
|
|
|
|
["jsonrpc"] = "2.0",
|
|
|
|
["id"] = id,
|
|
|
|
["error"] = new JsonObject
|
|
|
|
{
|
|
|
|
["code"] = -32700,
|
|
|
|
["message"] = "Method not found!",
|
|
|
|
}
|
|
|
|
};
|
|
|
|
_ = this.Transport.Write(response.ToJsonString()!);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(parsed["params"] is JsonArray || parsed["params"] is JsonObject))
|
|
|
|
{
|
|
|
|
if (id != null)
|
|
|
|
{
|
|
|
|
var response = new JsonObject
|
|
|
|
{
|
|
|
|
["jsonrpc"] = "2.0",
|
|
|
|
["id"] = id,
|
|
|
|
["error"] = new JsonObject
|
|
|
|
{
|
|
|
|
["code"] = -32602,
|
|
|
|
["message"] = "Invalid Parameters!",
|
|
|
|
}
|
|
|
|
};
|
|
|
|
_ = this.Transport.Write(response.ToJsonString()!);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_ = service.HandleRequest(functionName, parsed["params"]!, this.Context).ContinueWith(result =>
|
|
|
|
{
|
|
|
|
if (id != null)
|
|
|
|
{
|
|
|
|
var response = new JsonObject
|
|
|
|
{
|
|
|
|
["jsonrpc"] = "2.0",
|
|
|
|
["id"] = id,
|
|
|
|
["error"] = result.IsFaulted ? new JsonObject
|
|
|
|
{
|
|
|
|
["code"] = -32603,
|
|
|
|
["message"] = result.Exception!.InnerException!.Message
|
|
|
|
} : null,
|
|
|
|
["result"] = !result.IsFaulted ? result.Result : null,
|
|
|
|
};
|
|
|
|
_ = this.Transport.Write(response.ToJsonString()!);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: implement Notifications
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Ignoring everyting else. Don't care!
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception)
|
|
|
|
{
|
|
|
|
//TODO: Maybe log exception, but don't break!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async void SendNotification(string method, JsonArray param)
|
|
|
|
{
|
|
|
|
var not = new JsonObject
|
|
|
|
{
|
|
|
|
["jsonrpc"] = "2.0",
|
|
|
|
["method"] = method,
|
|
|
|
["params"] = param,
|
|
|
|
};
|
|
|
|
|
|
|
|
await this.Transport.Write(not.ToJsonString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract class JRpcService<TContext>
|
|
|
|
{
|
2022-01-07 22:10:24 +00:00
|
|
|
public abstract string Name { get; }
|
|
|
|
|
2022-01-05 21:16:17 +00:00
|
|
|
public HashSet<string> Functions = new HashSet<string>();
|
|
|
|
|
2022-01-07 22:10:24 +00:00
|
|
|
|
2022-01-05 21:16:17 +00:00
|
|
|
protected void RegisterFunction(string name)
|
|
|
|
{
|
|
|
|
this.Functions.Add(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract Task<JsonNode?> HandleRequest(string function, JsonNode param, TContext context);
|
|
|
|
// public abstract Task HandleNotification(string notification, JsonNode param);
|
|
|
|
}
|