using System; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; namespace Serein.Library.Network.WebSocketCommunication.Handle { /// /// 适用于Json数据格式的WebSocket消息处理类 /// public class WebSocketMsgHandleHelper { /// /// (Theme Name ,Data Name) - HandleModule /// public ConcurrentDictionary<(string, string), WebSocketHandleModule> MyHandleModuleDict = new ConcurrentDictionary<(string, string), WebSocketHandleModule>(); private Action> _onExceptionTracking; /// /// 异常跟踪 /// public event Action> OnExceptionTracking; /// /// 添加消息处理与异常处理 /// /// 模块配置 /// private WebSocketHandleModule AddMyHandleModule(WebSocketHandleModuleConfig moduleConfig) { var key = (moduleConfig.ThemeJsonKey, moduleConfig.DataJsonKey); if (!MyHandleModuleDict.TryGetValue(key, out var myHandleModule)) { myHandleModule = new WebSocketHandleModule(moduleConfig); MyHandleModuleDict[key] = myHandleModule; } return myHandleModule; } /// /// 移除某个模块的WebSocket消息处理 /// /// public void RemoveModule(ISocketHandleModule socketControlBase) { var type = socketControlBase.GetType(); var moduleAttribute = type.GetCustomAttribute(); if (moduleAttribute is null) { return; } var themeKeyName = moduleAttribute.ThemeKey; var dataKeyName = moduleAttribute.DataKey; var key = (themeKeyName, dataKeyName); if (MyHandleModuleDict.TryGetValue(key, out var myHandleModules)) { var isRemote = myHandleModules.RemoveConfig(socketControlBase); if (isRemote) MyHandleModuleDict.TryGetValue(key, out _); } } /// /// 添加消息处理以及异常处理 /// /// /// public void AddModule(ISocketHandleModule socketControlBase, Action> onExceptionTracking) { var type = socketControlBase.GetType(); var moduleAttribute = type.GetCustomAttribute(); if (moduleAttribute is null) { return; } var themeKey = moduleAttribute.ThemeKey; var dataKey = moduleAttribute.DataKey; var msgIdKey = moduleAttribute.MsgIdKey; var moduleConfig = new WebSocketHandleModuleConfig() { ThemeJsonKey = themeKey, DataJsonKey = dataKey, MsgIdJsonKey = msgIdKey, }; var handleModule = AddMyHandleModule(moduleConfig); var configs = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Select(methodInfo => { var methodsAttribute = methodInfo.GetCustomAttribute(); if (methodsAttribute is null) { return null; } else { if (string.IsNullOrEmpty(methodsAttribute.ThemeValue)) { methodsAttribute.ThemeValue = methodInfo.Name; } #region 生成处理配置 var config = new WebSocketHandleConfiguration(); config.ThemeValue = methodsAttribute.ThemeValue; config.ArgNotNull = methodsAttribute.ArgNotNull; config.IsReturnValue = methodsAttribute.IsReturnValue; //if (config.IsReturnValue) //{ // // 重新检查是否能够返回 // if (methodInfo.ReturnType == typeof(void)) // { // config.IsReturnValue = false; // void 不返回 // } // else if (methodInfo.ReturnType == typeof(Unit)) // { // config.IsReturnValue = false; // Unit 不返回 // } // else if (methodInfo.ReturnType == typeof(Task)) // { // config.IsReturnValue = false; // void 不返回 // } //} var parameterInfos = methodInfo.GetParameters(); config.DelegateDetails = new DelegateDetails(methodInfo); // 对应theme的emit构造委托调用工具类 config.Instance = socketControlBase; // 调用emit委托时的实例 config.OnExceptionTracking = onExceptionTracking; // 异常追踪 config.ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray(); // 入参参数类型 config.ParameterName = parameterInfos.Select(t => t.Name).ToArray(); // 入参参数名称 config.UseData = parameterInfos.Select(p => p.GetCustomAttribute() != null).ToArray(); // 是否使用整体data数据 config.UseMsgId = parameterInfos.Select(p => p.GetCustomAttribute() != null).ToArray(); // 是否使用消息ID #if NET5_0_OR_GREATER config.IsCheckArgNotNull = parameterInfos.Select(p => p.GetCustomAttribute() != null).ToArray(); // 是否检查null #endif if (config.IsCheckArgNotNull is null) { config.IsCheckArgNotNull = parameterInfos.Select(p => p.GetCustomAttribute() != null).ToArray(); // 是否检查null } else { // 兼容两种非空特性的写法 var argNotNull = parameterInfos.Select(p => p.GetCustomAttribute() != null).ToArray(); // 是否检查null for (int i = 0; i < config.IsCheckArgNotNull.Length; i++) { if (!config.IsCheckArgNotNull[i] && argNotNull[i]) { config.IsCheckArgNotNull[i] = true; } } } #endregion var value = methodsAttribute.ThemeValue; return config; } }) .Where(config => config != null).ToList(); if (configs.Count == 0) { return; } Console.WriteLine($"add websocket handle model :"); Console.WriteLine($"theme key, data key : {themeKey}, {dataKey}"); foreach (var config in configs) { Console.WriteLine($"theme value : {config.ThemeValue} "); var result = handleModule.AddHandleConfigs(config); } } /// /// 异步处理消息 /// /// 此次请求的上下文 /// public void Handle(WebSocketMsgContext context) { foreach (var module in MyHandleModuleDict.Values) { if (context.Handle) { return; } _ = module.HandleAsync(context); } } } }