using Serein.Library;
using Serein.Library.Utils;
using Serein.Proto.WebSocket.Attributes;
using Serein.Proto.WebSocket.Handle;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Reactive;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using NetWebSocket = System.Net.WebSockets.WebSocket;
namespace Serein.Proto.WebSocket
{
///
/// WebSocket 服务类,负责管理所有 WebSocket 连接和处理模块
///
public partial class SereinWebSocketService : ISereinWebSocketService
{
///
/// (Theme Name ,Data Name) - HandleModule
///
private readonly ConcurrentDictionary<(string, string), WebSocketHandleModule> _socketModules;
///
/// 追踪未处理的异常
///
private Action? _onExceptionTracking;
private Action? _onReply;
private Func _onReplyMakeData;
///
/// 维护所有 WebSocket 连接
///
private readonly List _sockets;
///
/// 用于增加、移除 WebSocket 连接时,保证线程安全操作
///
private readonly object _lock = new object();
public int ConcetionCount => _sockets.Count;
///
/// SereinWebSocketService 构造函数,初始化 WebSocket 模块字典和连接列表
///
public SereinWebSocketService()
{
_socketModules = new ConcurrentDictionary<(string, string), WebSocketHandleModule>();
_sockets = new List();
_lock = new object();
}
#region 添加处理模块
///
/// 添加处理模块,使用指定的实例工厂和异常追踪回调
///
///
///
///
public ISereinWebSocketService AddHandleModule() where T : ISocketHandleModule, new()
{
var type = typeof(T);
Func instanceFactory = () => (T)Activator.CreateInstance(type);
return AddHandleModule(type, instanceFactory);
}
///
/// 添加处理模块,使用指定的实例工厂和异常追踪回调
///
///
///
///
public ISereinWebSocketService AddHandleModule(Func instanceFactory) where T : ISocketHandleModule
{
var type = typeof(T);
return AddHandleModule(type, instanceFactory);
}
///
/// 添加处理模块,使用指定的类型、实例工厂和异常追踪回调
///
///
///
///
private ISereinWebSocketService AddHandleModule(Type type, Func instanceFactory)
{
if(!CheckAttribute(type, out var attribute))
{
throw new Exception($"类型 {type} 需要标记 WebSocketModuleAttribute 特性");
}
var modbuleConfig = GetConfig(attribute);
var module = GetOrAddModule(modbuleConfig);
var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToArray();
var methodConfigs = CreateMethodConfig(methodInfos, instanceFactory);
SereinEnv.WriteLine(InfoType.INFO, $"add websocket handle model :");
SereinEnv.WriteLine(InfoType.INFO, $"theme key, data key : {modbuleConfig.ThemeJsonKey}, {modbuleConfig.DataJsonKey}");
foreach (var methodConfig in methodConfigs)
{
SereinEnv.WriteLine(InfoType.INFO, $"theme value : {methodConfig!.ThemeValue} ");
var result = module.AddHandleConfigs(methodConfig);
}
return this;
}
///
/// 检查特性
///
///
///
///
///
private bool CheckAttribute(Type type, out TAttribute attribute) where TAttribute : Attribute
{
attribute = type.GetCustomAttribute();
if (attribute is null)
{
return false;
}
return true;
}
///
/// 获取模块配置
///
///
///
private WebSocketModuleConfig GetConfig(WebSocketModuleAttribute moduleAttribute)
{
var themeKey = moduleAttribute.ThemeKey;
var dataKey = moduleAttribute.DataKey;
var msgIdKey = moduleAttribute.MsgIdKey;
var isResponseUseReturn = moduleAttribute.IsResponseUseReturn;
var moduleConfig = new WebSocketModuleConfig()
{
ThemeJsonKey = themeKey,
DataJsonKey = dataKey,
MsgIdJsonKey = msgIdKey,
IsResponseUseReturn = isResponseUseReturn,
};
return moduleConfig;
}
///
/// 获取或添加消息处理与异常处理
///
/// 模块配置
///
private WebSocketHandleModule GetOrAddModule(WebSocketModuleConfig moduleConfig)
{
var key = (moduleConfig.ThemeJsonKey, moduleConfig.DataJsonKey);
if (_socketModules.TryGetValue(key, out var wsHandleModule))
{
return wsHandleModule;
}
wsHandleModule = new WebSocketHandleModule(moduleConfig);
_socketModules[key] = wsHandleModule;
return wsHandleModule;
}
///
/// 创建方法配置
///
///
///
///
///
private List CreateMethodConfig(MethodInfo[] methodInfos, Func instanceFactory)
{
List configs = [];
foreach (var methodInfo in methodInfos)
{
var wsMethodAttribute = methodInfo.GetCustomAttribute();
if (wsMethodAttribute is null)
{
continue;
}
var parameterInfos = methodInfo.GetParameters();
var temp_array = parameterInfos.Select(p =>
{
var isSend = CheckSendType(p.ParameterType, out var sendType);
return new
{
IsNeedSend = isSend,
Type = sendType
};
}).ToArray();
var config = new WebSocketMethodConfig
{
ThemeValue = string.IsNullOrEmpty(wsMethodAttribute.ThemeValue) ? methodInfo.Name : wsMethodAttribute.ThemeValue,
IsReturnValue = wsMethodAttribute.IsReturnValue,
DelegateDetails = new DelegateDetails(methodInfo), // 对应theme的emit构造委托调用工具类
InstanceFactory = instanceFactory, // 调用emit委托时的实例
//OnExceptionTracking = onExceptionTracking, // 异常追踪
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray(), // 入参参数类型
ParameterName = parameterInfos.Select(t => $"{t.Name}").ToArray(), // 入参参数名称
UseRequest = parameterInfos.Select(p => p.GetCustomAttribute() is not null).ToArray(),// 是否使用整体data数据
UseData = parameterInfos.Select(p => p.GetCustomAttribute() is not null).ToArray(), // 是否使用整体data数据
UseMsgId = parameterInfos.Select(p => p.GetCustomAttribute() is not null).ToArray(), // 是否使用消息ID
UseContent = parameterInfos.Select(p => p.ParameterType.IsAssignableFrom(typeof(WebSocketHandleContext))).ToArray(), // 是否使用上下文
IsNeedSendDelegate = temp_array.Select(p => p.IsNeedSend).ToArray(), // 是否需要发送消息的委托
SendDelegateType = temp_array.Select(p => p.Type).ToArray(), // 发送消息的委托类型
CachedSendDelegates = new Delegate[temp_array.Length], // 提前缓存发送委托数组
};
configs.Add(config);
}
return configs;
}
private bool CheckSendType(Type type , out SendType sendType)
{
if (type.IsAssignableFrom(typeof(Func