//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using TouchSocket.Core;
using TouchSocket.Http;
using TouchSocket.Http.WebSockets;
using TouchSocket.Sockets;
namespace TouchSocket.Rpc.JsonRpc
{
///
/// JsonRpcParser解析器插件
///
public class JsonRpcParserPlugin : WebSocketPluginBase, IRpcParser
{
private readonly ActionMap m_actionMap;
private string m_jsonRpcUrl = "/jsonrpc";
private RpcStore m_rpcStore;
///
/// 构造函数
///
public JsonRpcParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore)
{
m_actionMap = new ActionMap();
rpcStore?.AddRpcParser(GetType().Name, this);
}
///
/// JsonRpc的调用键。
///
public ActionMap ActionMap => m_actionMap;
///
/// 自动转换协议
///
public bool AutoSwitch { get; set; } = true;
///
/// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。
///
public string JsonRpcUrl
{
get => m_jsonRpcUrl;
set => m_jsonRpcUrl = string.IsNullOrEmpty(value) ? "/" : value;
}
///
///
///
public RpcStore RpcStore => m_rpcStore;
///
/// 不需要自动转化协议。
/// 仅当服务器是TCP时生效。此时如果携带协议为TcpJsonRpc时才会解释为jsonRpc。
///
///
public JsonRpcParserPlugin NoSwitchProtocol()
{
AutoSwitch = false;
return this;
}
#region RPC解析器
void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances)
{
foreach (var methodInstance in methodInstances)
{
if (methodInstance.GetAttribute() is JsonRpcAttribute attribute)
{
m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance);
}
}
}
void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances)
{
foreach (var methodInstance in methodInstances)
{
if (methodInstance.GetAttribute() is JsonRpcAttribute attribute)
{
m_actionMap.Remove(attribute.GetInvokenKey(methodInstance));
}
}
}
void IRpcParser.SetRpcStore(RpcStore rpcService)
{
m_rpcStore = rpcService;
}
#endregion RPC解析器
///
/// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。
///
///
///
public JsonRpcParserPlugin SetJsonRpcUrl(string jsonRpcUrl)
{
JsonRpcUrl = jsonRpcUrl;
return this;
}
///
///
///
///
///
protected override void OnConnecting(ITcpClientBase client, OperationEventArgs e)
{
if (AutoSwitch && client.Protocol == Protocol.TCP)
{
client.SwitchProtocolToTcpJsonRpc();
}
base.OnConnecting(client, e);
}
///
///
///
///
///
protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e)
{
if (e.DataFrame.Opcode == WSDataType.Text)
{
string jsonRpcStr = e.DataFrame.ToText();
if (jsonRpcStr.Contains("jsonrpc"))
{
e.Handled = true;
ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext()
{
Caller = client,
JRPT = JRPT.Websocket,
JsonString = jsonRpcStr
});
}
}
}
///
///
///
///
///
protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e)
{
if (m_jsonRpcUrl == "/" || e.Context.Request.UrlEquals(m_jsonRpcUrl))
{
e.Handled = true;
ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext()
{
Caller = client,
JRPT = JRPT.Http,
JsonString = e.Context.Request.GetBody(),
HttpContext = e.Context
});
}
base.OnPost(client, e);
}
///
///
///
///
///
protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e)
{
if (client.Protocol == JsonRpcConfigExtensions.TcpJsonRpc)
{
string jsonRpcStr = e.ByteBlock.ToString();
if (jsonRpcStr.Contains("jsonrpc"))
{
e.Handled = true;
ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext()
{
Caller = client,
JRPT = JRPT.Tcp,
JsonString = e.ByteBlock.ToString()
});
}
}
base.OnReceivedData(client, e);
}
private static void Response(JsonRpcCallContext callContext, object result, error error)
{
try
{
using (ByteBlock responseByteBlock = new ByteBlock())
{
object jobject = null;
if (error == null)
{
jobject = new JsonRpcSuccessResponse
{
result = result,
id = callContext.JsonRpcContext.id
};
}
else
{
jobject = new JsonRpcErrorResponse
{
error = error,
id = callContext.JsonRpcContext.id
};
}
ITcpClientBase client = (ITcpClientBase)callContext.Caller;
if (callContext.JRPT == JRPT.Http)
{
HttpResponse httpResponse = callContext.HttpContext.Response;
httpResponse.FromJson(jobject.ToJson());
httpResponse.Answer();
}
else if (callContext.JRPT == JRPT.Websocket)
{
((HttpSocketClient)client).SendWithWS(jobject.ToJson());
}
else
{
responseByteBlock.Write(jobject.ToJson().ToUTF8Bytes());
client.Send(responseByteBlock);
}
}
}
catch
{
}
}
private void BuildRequestContext(ref JsonRpcCallContext callContext)
{
JsonRpcContext jsonRpcContext = SerializeConvert.JsonDeserializeFromString(callContext.JsonString);
callContext.JsonRpcContext = jsonRpcContext;
if (jsonRpcContext.id != null)
{
jsonRpcContext.needResponse = true;
}
if (m_actionMap.TryGetMethodInstance(jsonRpcContext.method, out MethodInstance methodInstance))
{
callContext.MethodInstance = methodInstance;
if (jsonRpcContext.@params == null)
{
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
if (methodInstance.ParameterNames.Length > 1)
{
throw new RpcException("调用参数计数不匹配");
}
else
{
jsonRpcContext.parameters = new object[] { callContext };
}
}
else
{
if (methodInstance.ParameterNames.Length != 0)
{
throw new RpcException("调用参数计数不匹配");
}
}
}
if (jsonRpcContext.@params is Dictionary obj)
{
jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length];
//内联
int i = 0;
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
jsonRpcContext.parameters[0] = callContext;
i = 1;
}
for (; i < methodInstance.ParameterNames.Length; i++)
{
if (obj.TryGetValue(methodInstance.ParameterNames[i], out object jToken))
{
Type type = methodInstance.ParameterTypes[i];
jsonRpcContext.parameters[i] = jToken.ToJson().FromJson(type);
}
else if (methodInstance.Parameters[i].HasDefaultValue)
{
jsonRpcContext.parameters[i] = methodInstance.Parameters[i].DefaultValue;
}
else
{
throw new RpcException("调用参数计数不匹配");
}
}
}
else
{
IList array = (IList)jsonRpcContext.@params;
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
if (array.Count != methodInstance.ParameterNames.Length - 1)
{
throw new RpcException("调用参数计数不匹配");
}
jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length];
jsonRpcContext.parameters[0] = callContext;
for (int i = 0; i < array.Count; i++)
{
jsonRpcContext.parameters[i + 1] = array[i].ToJson().FromJson(methodInstance.ParameterTypes[i + 1]);
}
}
else
{
if (array.Count != methodInstance.ParameterNames.Length)
{
throw new RpcException("调用参数计数不匹配");
}
jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length];
for (int i = 0; i < array.Count; i++)
{
jsonRpcContext.parameters[i] = array[i].ToJson().FromJson(methodInstance.ParameterTypes[i]);
}
}
}
}
}
private void InvokeWaitCallback(object context)
{
if (context is null)
{
return;
}
JsonRpcCallContext callContext = (JsonRpcCallContext)context;
InvokeResult invokeResult = new InvokeResult();
try
{
BuildRequestContext(ref callContext);
}
catch (Exception ex)
{
invokeResult.Status = InvokeStatus.Exception;
invokeResult.Message = ex.Message;
}
if (callContext.MethodInstance != null)
{
if (!callContext.MethodInstance.IsEnable)
{
invokeResult.Status = InvokeStatus.UnEnable;
}
}
else
{
invokeResult.Status = InvokeStatus.UnFound;
}
if (invokeResult.Status == InvokeStatus.Ready)
{
IRpcServer rpcServer = callContext.MethodInstance.ServerFactory.Create(callContext, callContext.JsonRpcContext.parameters);
if (rpcServer is ITransientRpcServer transientRpcServer)
{
transientRpcServer.CallContext = callContext;
}
invokeResult = m_rpcStore.Execute(rpcServer, callContext.JsonRpcContext.parameters, callContext);
}
if (!callContext.JsonRpcContext.needResponse)
{
return;
}
error error = null;
switch (invokeResult.Status)
{
case InvokeStatus.Success:
{
break;
}
case InvokeStatus.UnFound:
{
error = new error();
error.code = -32601;
error.message = "函数未找到";
break;
}
case InvokeStatus.UnEnable:
{
error = new error();
error.code = -32601;
error.message = "函数已被禁用";
break;
}
case InvokeStatus.InvocationException:
{
error = new error();
error.code = -32603;
error.message = "函数内部异常";
break;
}
case InvokeStatus.Exception:
{
error = new error();
error.code = -32602;
error.message = invokeResult.Message;
break;
}
default:
return;
}
Response(callContext, invokeResult.Result, error);
}
}
}