//------------------------------------------------------------------------------ // 此代码版权(除特别声明或在RRQMCore.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 // 交流QQ群:234762506 // 感谢您的下载和使用 //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ using RRQMCore.ByteManager; using RRQMCore.Log; using RRQMCore.XREF.Newtonsoft.Json; using RRQMCore.XREF.Newtonsoft.Json.Linq; using RRQMSocket.Http; using System; using System.Text; namespace RRQMSocket.RPC.JsonRpc { /// /// JsonRpcParser解析器 /// public class JsonRpcParser : TcpService, IRPCParser { private ActionMap actionMap; private MethodMap methodMap; private JsonRpcProtocolType protocolType; /// /// 构造函数 /// public JsonRpcParser() { this.actionMap = new ActionMap(); } /// /// 函数键映射图 /// public ActionMap ActionMap { get { return this.actionMap; } } private int maxPackageSize; /// /// 最大数据包长度 /// public int MaxPackageSize { get { return maxPackageSize; } } /// /// 函数映射 /// public MethodMap MethodMap { get { return methodMap; } } /// /// 协议类型 /// public JsonRpcProtocolType ProtocolType { get { return protocolType; } } /// /// 所属服务器 /// public RPCService RPCService { get; private set; } /// /// 执行函数 /// public Action RRQMExecuteMethod { get; private set; } /// /// 结束调用 /// /// /// public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance) { ISocketClient socketClient = (ISocketClient)methodInvoker.Caller; error error = new error(); switch (methodInvoker.Status) { case InvokeStatus.Success: { error = null; break; } case InvokeStatus.UnFound: { error.code = -32601; error.message = "函数未找到"; break; } case InvokeStatus.UnEnable: { error.code = -32601; error.message = "函数已被禁用"; break; } case InvokeStatus.Abort: { error.code = -32601; error.message = "函数已被中断执行"; break; } case InvokeStatus.InvocationException: { error.code = -32603; error.message = "函数内部异常"; break; } case InvokeStatus.Exception: { error.code = -32602; error.message = methodInvoker.StatusMessage; break; } } JsonRequestContext jsonRequestContext = (JsonRequestContext)methodInvoker.Flag; if (jsonRequestContext.needResponse) { ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); this.BuildResponseByteBlock(byteBlock, methodInvoker, jsonRequestContext.id, methodInvoker.ReturnParameter, error); if (socketClient.Online) { try { string s = Encoding.UTF8.GetString(byteBlock.ToArray()); socketClient.Send(byteBlock); } catch (Exception ex) { this.Logger.Debug(LogType.Error, this, ex.Message); } finally { byteBlock.Dispose(); } } } } /// /// 初始化 /// /// /// public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances) { foreach (var methodInstance in methodInstances) { foreach (var att in methodInstance.RPCAttributes) { if (att is JsonRpcAttribute attribute) { if (methodInstance.IsByRef) { throw new RRQMRPCException($"JsonRpc服务中不允许有out及ref关键字,服务:{methodInstance.Method.Name}"); } string actionKey = string.IsNullOrEmpty(attribute.MethodKey) ? methodInstance.Method.Name : attribute.MethodKey; try { this.actionMap.Add(actionKey, methodInstance); } catch { throw new RRQMRPCException($"函数键为{actionKey}的方法已注册。"); } } } } } /// /// 取消注册服务 /// /// /// public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances) { } /// /// 设置执行委托 /// /// public void SetExecuteMethod(Action executeMethod) { this.RRQMExecuteMethod = executeMethod; } /// /// 设置地图映射 /// /// public void SetMethodMap(MethodMap methodMap) { this.methodMap = methodMap; } /// /// 设置服务 /// /// public void SetRPCService(RPCService service) { this.RPCService = service; } /// /// 构建请求内容 /// /// 数据 /// 调用服务实例 /// /// protected virtual void BuildRequestContext(string jsonString, out MethodInstance methodInstance, out JsonRequestContext context) { try { context = JsonConvert.DeserializeObject(jsonString); if (context.id != null) { context.needResponse = true; } } catch (Exception ex) { context = new JsonRequestContext(); context.needResponse = true; throw ex; } if (this.actionMap.TryGet(context.method, out methodInstance)) { if (context.@params == null) { if (methodInstance.ParameterNames.Length != 0) { throw new RRQMRPCException("调用参数计数不匹配"); } return; } if (context.@params.GetType() != typeof(JArray)) { JObject obj = (JObject)context.@params; context.parameters = new object[methodInstance.ParameterNames.Length]; //内联 for (int i = 0; i < methodInstance.ParameterNames.Length; i++) { if (obj.TryGetValue(methodInstance.ParameterNames[i], out JToken jToken)) { Type type = methodInstance.ParameterTypes[i]; context.parameters[i] = jToken.ToObject(type); } else if (methodInstance.Parameters[i].HasDefaultValue) { context.parameters[i] = methodInstance.Parameters[i].DefaultValue; } else { throw new RRQMRPCException("调用参数计数不匹配"); } } } else { JArray array = (JArray)context.@params; if (array.Count != methodInstance.ParameterNames.Length) { throw new RRQMRPCException("调用参数计数不匹配"); } context.parameters = new object[methodInstance.ParameterNames.Length]; for (int i = 0; i < array.Count; i++) { context.parameters[i] = context.@params[i].ToObject(methodInstance.ParameterTypes[i]); } } } else { methodInstance = null; } } /// /// 构建响应数据 /// /// /// /// /// /// protected virtual void BuildResponseByteBlock(ByteBlock responseByteBlock, MethodInvoker methodInvoker, string id, object result, error error) { JObject jobject = new JObject(); if (error == null) { //成功 jobject.Add("jsonrpc", JToken.FromObject("2.0")); jobject.Add("result", result == null ? null : JToken.FromObject(result)); jobject.Add("id", id == null ? null : JToken.FromObject(id)); } else { jobject.Add("jsonrpc", JToken.FromObject("2.0")); jobject.Add("error", JToken.FromObject(error)); jobject.Add("id", id == null ? null : JToken.FromObject(id)); } switch (this.protocolType) { case JsonRpcProtocolType.Tcp: { responseByteBlock.Write(Encoding.UTF8.GetBytes(jobject.ToString(Formatting.None))); break; } case JsonRpcProtocolType.Http: { HttpResponse httpResponse = new HttpResponse(); httpResponse.FromJson(jobject.ToString(Formatting.None)); httpResponse.Build(responseByteBlock); break; } } } /// /// 载入配置 /// /// protected override void LoadConfig(ServiceConfig serviceConfig) { base.LoadConfig(serviceConfig); this.protocolType = (JsonRpcProtocolType)serviceConfig.GetValue(JsonRpcParserConfig.ProtocolTypeProperty); this.maxPackageSize = (int)serviceConfig.GetValue(JsonRpcParserConfig.MaxPackageSizeProperty); } /// /// 创建SocketCliect /// /// /// protected override void OnCreateSocketCliect(JsonRpcSocketClient socketClient, CreateOption createOption) { if (createOption.NewCreate) { socketClient.OnReceived = this.OnReceived; } switch (this.protocolType) { case JsonRpcProtocolType.Tcp: socketClient.SetAdapter(new TerminatorDataHandlingAdapter(this.maxPackageSize, "\r\n")); break; case JsonRpcProtocolType.Http: socketClient.SetAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Server)); break; } } private void OnReceived(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj) { MethodInvoker methodInvoker = new MethodInvoker(); methodInvoker.Caller = socketClient; MethodInstance methodInstance = null; JsonRequestContext context = null; try { string jsonString = null; switch (this.protocolType) { case JsonRpcProtocolType.Tcp: { jsonString = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); break; } case JsonRpcProtocolType.Http: { HttpRequest httpRequest = (HttpRequest)obj; jsonString = httpRequest.Body; methodInvoker.Flag = httpRequest; break; } } this.BuildRequestContext(jsonString, out methodInstance, out context); if (methodInstance == null) { methodInvoker.Status = InvokeStatus.UnFound; } else if (methodInstance.IsEnable) { methodInvoker.Parameters = context.parameters; } else { methodInvoker.Status = InvokeStatus.UnEnable; } } catch (Exception ex) { methodInvoker.Status = InvokeStatus.Exception; methodInvoker.StatusMessage = ex.Message; } methodInvoker.Flag = context; this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance); } } }