using Serein.Library; using Serein.Proto.WebSocket.Attributes; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Threading.Tasks; namespace Serein.Proto.WebSocket.Handle { /// /// 适用于Json数据格式的WebSocket消息处理类 /// public class WebSocketMsgHandleHelper { /// /// (Theme Name ,Data Name) - HandleModule /// public ConcurrentDictionary<(string, string), WebSocketHandleModule> MyHandleModuleDict = new ConcurrentDictionary<(string, string), WebSocketHandleModule>(); /// /// 异常跟踪 /// public Action>? OnExceptionTracking; /// /// 添加消息处理与异常处理 /// /// 模块配置 /// private WebSocketHandleModule AddMsgHandleModule(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(Func instanceFactory, Action> onExceptionTracking) where T : ISocketHandleModule { var type = typeof(T); var moduleAttribute = type.GetCustomAttribute(); if (moduleAttribute is null) { return; } var themeKey = moduleAttribute.ThemeKey; var dataKey = moduleAttribute.DataKey; var msgIdKey = moduleAttribute.MsgIdKey; var isResponseUseReturn = moduleAttribute.IsResponseUseReturn; var moduleConfig = new WebSocketHandleModuleConfig() { ThemeJsonKey = themeKey, DataJsonKey = dataKey, MsgIdJsonKey = msgIdKey, IsResponseUseReturn = isResponseUseReturn, }; var handleModule = AddMsgHandleModule(moduleConfig); var configs = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Select(methodInfo => { var methodsAttribute = methodInfo.GetCustomAttribute(); if (methodsAttribute is null) { return default; } else { if (string.IsNullOrEmpty(methodsAttribute.ThemeValue)) { methodsAttribute.ThemeValue = methodInfo.Name; } var config = new WebSocketMethodHandleConfig(); 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.InstanceFactory = instanceFactory; // 调用emit委托时的实例 config.OnExceptionTracking = onExceptionTracking; // 异常追踪 config.ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray(); // 入参参数类型 config.ParameterName = parameterInfos.Select(t => $"{t.Name}").ToArray(); // 入参参数名称 config.UseRequest = parameterInfos.Select(p => p.GetCustomAttribute() != null).ToArray(); // 是否使用整体data数据 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 var value = methodsAttribute.ThemeValue; return config; } }) .Where(config => config != null).ToList(); if (configs.Count == 0) { return; } SereinEnv.WriteLine(InfoType.INFO, $"add websocket handle model :"); SereinEnv.WriteLine(InfoType.INFO, $"theme key, data key : {themeKey}, {dataKey}"); foreach (var config in configs) { SereinEnv.WriteLine(InfoType.INFO, $"theme value : {config!.ThemeValue} "); var result = handleModule.AddHandleConfigs(config); } } /// /// 异步处理消息 /// /// 此次请求的上下文 /// public async Task HandleAsync(WebSocketMsgContext context) { foreach (var module in MyHandleModuleDict.Values) { if (context.Handle) { return; } await module.HandleAsync(context); } } } }