From 6fc57458a776339a99a493ba0b334e564e38980c Mon Sep 17 00:00:00 2001
From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com>
Date: Sat, 2 Aug 2025 10:48:31 +0800
Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=96=B0=E8=AE=BE=E8=AE=A1=E4=BA=86Li?=
=?UTF-8?q?bray.Json=20Api=E4=BB=A5=E5=8F=8A=20WebSocket=20=E7=9A=84?=
=?UTF-8?q?=E4=BA=A4=E4=BA=92=E5=A4=84=E7=90=86=E6=96=B9=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Library/Api/IJsonProvider.cs | 31 +-
Library/ScriptBaseFunc.cs | 9 +-
Library/Utils/JsonHelper.cs | 1 -
.../NewtonsoftJsonArrayToken.cs | 3 +
.../NewtonsoftJsonObjectToken.cs | 3 +
.../NewtonsoftJsonValueToken.cs | 3 +
.../Attributes/SendAttribute.cs | 15 +
.../Attributes/UseRequestAttribute.cs | 5 +-
...tribute.cs => WebSocketModuleAttribute.cs} | 6 +-
...andleAttribute.cs => WsMethodAttribute.cs} | 8 +-
Serein.Proto.WebSocket/Handle/Attribute.cs | 14 -
...ration.cs => MethodInvokeConfiguration.cs} | 33 +-
.../Handle/WebSocketHandleModule.cs | 247 ++++++-----
...figuration.cs => WebSocketMethodConfig.cs} | 2 +-
...duleConfig.cs => WebSocketModuleConfig.cs} | 5 +-
.../Handle/WebSocketMsgHandleHelper.cs | 39 +-
.../ISereinWebSocketService.cs | 55 +++
Serein.Proto.WebSocket/ISocketHandleModule.cs | 5 +-
Serein.Proto.WebSocket/SendType.cs | 30 ++
.../Serein.Proto.WebSocket.csproj | 12 +-
.../SereinWebSocketService.cs | 400 ++++++++++++++++++
Serein.Proto.WebSocket/SocketExtension.cs | 29 ++
Serein.Proto.WebSocket/TestClass.cs | 37 ++
Serein.Proto.WebSocket/WebSocketClient.cs | 100 +----
...sgContext.cs => WebSocketHandleContext.cs} | 82 ++--
...cs => WebSocketMessageTransmissionTool.cs} | 37 +-
Serein.Proto.WebSocket/WebSocketServer.cs | 6 +-
Workbench/App.xaml.cs | 2 +-
Workbench/Test.cs | 12 +
29 files changed, 883 insertions(+), 348 deletions(-)
create mode 100644 Serein.Proto.WebSocket/Attributes/SendAttribute.cs
rename Serein.Proto.WebSocket/Attributes/{AutoSocketModuleAttribute.cs => WebSocketModuleAttribute.cs} (82%)
rename Serein.Proto.WebSocket/Attributes/{AutoSocketHandleAttribute.cs => WsMethodAttribute.cs} (83%)
delete mode 100644 Serein.Proto.WebSocket/Handle/Attribute.cs
rename Serein.Proto.WebSocket/Handle/{HandleConfiguration.cs => MethodInvokeConfiguration.cs} (78%)
rename Serein.Proto.WebSocket/Handle/{WebSocketHandleConfiguration.cs => WebSocketMethodConfig.cs} (73%)
rename Serein.Proto.WebSocket/Handle/{WebSocketHandleModuleConfig.cs => WebSocketModuleConfig.cs} (94%)
create mode 100644 Serein.Proto.WebSocket/ISereinWebSocketService.cs
create mode 100644 Serein.Proto.WebSocket/SendType.cs
create mode 100644 Serein.Proto.WebSocket/SereinWebSocketService.cs
create mode 100644 Serein.Proto.WebSocket/SocketExtension.cs
create mode 100644 Serein.Proto.WebSocket/TestClass.cs
rename Serein.Proto.WebSocket/{Handle/WebSocketMsgContext.cs => WebSocketHandleContext.cs} (52%)
rename Serein.Proto.WebSocket/{TestExtension.cs => WebSocketMessageTransmissionTool.cs} (59%)
create mode 100644 Workbench/Test.cs
diff --git a/Library/Api/IJsonProvider.cs b/Library/Api/IJsonProvider.cs
index 30e2b5f..744a701 100644
--- a/Library/Api/IJsonProvider.cs
+++ b/Library/Api/IJsonProvider.cs
@@ -7,11 +7,36 @@ using System.Threading.Tasks;
namespace Serein.Library.Api
{
+
+
///
/// JSON数据交互的Token接口,允许使用不同的JSON库进行数据处理。
///
public interface IJsonToken
{
+ ///
+ /// 获取当前Token的类型,可能是值、对象或数组。
+ ///
+ TokenType Type { get; }
+
+ ///
+ /// 获取当前Token的类型,可能是值、对象或数组。
+ ///
+ public enum TokenType
+ {
+ ///
+ /// 表示一个值类型的Token,例如字符串、数字或布尔值。
+ ///
+ Value,
+ ///
+ /// 表示一个对象类型的Token,通常是一个键值对集合。
+ ///
+ Object,
+ ///
+ /// 表示一个数组类型的Token,通常是一个元素列表。
+ ///
+ Array,
+ }
///
/// 获取 Token
///
@@ -19,12 +44,6 @@ namespace Serein.Library.Api
///
IJsonToken this[object name] { get; }
- /* ///
- /// 获取 Token 数组的元素,允许通过索引访问数组中的元素。
- ///
- ///
- ///
- IJsonToken this[int index] { get; }*/
///
/// 获取指定名称的属性,如果存在则返回true,并通过out参数返回对应的IJsonToken对象。
diff --git a/Library/ScriptBaseFunc.cs b/Library/ScriptBaseFunc.cs
index 24f0787..25b782b 100644
--- a/Library/ScriptBaseFunc.cs
+++ b/Library/ScriptBaseFunc.cs
@@ -145,15 +145,14 @@ namespace Serein.Library
///
public static IJsonToken json(string content)
{
+ /*if (string.IsNullOrWhiteSpace(content))
+ {
+ return JsonHelper.Object(dict => { }) ;
+ }*/
return JsonHelper.Parse(content);
}
-
-
-
-
-
#endregion
diff --git a/Library/Utils/JsonHelper.cs b/Library/Utils/JsonHelper.cs
index bbcdd2f..41b12b8 100644
--- a/Library/Utils/JsonHelper.cs
+++ b/Library/Utils/JsonHelper.cs
@@ -56,7 +56,6 @@ namespace Serein.Library.Utils
public static IJsonToken Parse(string json)
{
return provider.Parse(json);
-
}
///
diff --git a/Serein.Extend.NewtonsoftJson/NewtonsoftJsonArrayToken.cs b/Serein.Extend.NewtonsoftJson/NewtonsoftJsonArrayToken.cs
index 0ac901d..470eb01 100644
--- a/Serein.Extend.NewtonsoftJson/NewtonsoftJsonArrayToken.cs
+++ b/Serein.Extend.NewtonsoftJson/NewtonsoftJsonArrayToken.cs
@@ -6,11 +6,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using static Serein.Library.Api.IJsonToken;
namespace Serein.Extend.NewtonsoftJson
{
public sealed class NewtonsoftJsonArrayToken : IJsonToken, IList
{
+ public TokenType Type => TokenType.Array;
+
private readonly JArray _array;
public NewtonsoftJsonArrayToken(JArray array) => _array = array;
diff --git a/Serein.Extend.NewtonsoftJson/NewtonsoftJsonObjectToken.cs b/Serein.Extend.NewtonsoftJson/NewtonsoftJsonObjectToken.cs
index 8e7404c..d74e938 100644
--- a/Serein.Extend.NewtonsoftJson/NewtonsoftJsonObjectToken.cs
+++ b/Serein.Extend.NewtonsoftJson/NewtonsoftJsonObjectToken.cs
@@ -5,6 +5,7 @@ using Serein.Library.Utils;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using static Serein.Library.Api.IJsonToken;
namespace Serein.Extend.NewtonsoftJson
{
@@ -13,6 +14,8 @@ namespace Serein.Extend.NewtonsoftJson
///
public sealed class NewtonsoftJsonObjectToken : IJsonToken, IDictionary
{
+ public TokenType Type => TokenType.Object;
+
private readonly JObject _object;
public NewtonsoftJsonObjectToken(JObject obj) => _object = obj;
diff --git a/Serein.Extend.NewtonsoftJson/NewtonsoftJsonValueToken.cs b/Serein.Extend.NewtonsoftJson/NewtonsoftJsonValueToken.cs
index 9f3540b..6b8f1b7 100644
--- a/Serein.Extend.NewtonsoftJson/NewtonsoftJsonValueToken.cs
+++ b/Serein.Extend.NewtonsoftJson/NewtonsoftJsonValueToken.cs
@@ -6,11 +6,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using static Serein.Library.Api.IJsonToken;
namespace Serein.Extend.NewtonsoftJson
{
public sealed class NewtonsoftJsonValueToken : IJsonToken
{
+ public TokenType Type => TokenType.Value;
+
private readonly JToken _token;
public NewtonsoftJsonValueToken(JToken token)
diff --git a/Serein.Proto.WebSocket/Attributes/SendAttribute.cs b/Serein.Proto.WebSocket/Attributes/SendAttribute.cs
new file mode 100644
index 0000000..54ff108
--- /dev/null
+++ b/Serein.Proto.WebSocket/Attributes/SendAttribute.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Proto.WebSocket.Attributes
+{
+ ///
+ /// 指示需要发送消息的处理方法
+ ///
+ public sealed class SendAttribute : Attribute
+ {
+ }
+}
diff --git a/Serein.Proto.WebSocket/Attributes/UseRequestAttribute.cs b/Serein.Proto.WebSocket/Attributes/UseRequestAttribute.cs
index cbb2367..f6183bd 100644
--- a/Serein.Proto.WebSocket/Attributes/UseRequestAttribute.cs
+++ b/Serein.Proto.WebSocket/Attributes/UseRequestAttribute.cs
@@ -6,7 +6,10 @@ using System.Threading.Tasks;
namespace Serein.Proto.WebSocket.Attributes
{
- internal sealed class UseRequestAttribute : Attribute
+ ///
+ /// 指示使用 WebSocket 中请求的整体数据
+ ///
+ public sealed class UseRequestAttribute : Attribute
{
}
}
diff --git a/Serein.Proto.WebSocket/Attributes/AutoSocketModuleAttribute.cs b/Serein.Proto.WebSocket/Attributes/WebSocketModuleAttribute.cs
similarity index 82%
rename from Serein.Proto.WebSocket/Attributes/AutoSocketModuleAttribute.cs
rename to Serein.Proto.WebSocket/Attributes/WebSocketModuleAttribute.cs
index 43c9734..ae23a90 100644
--- a/Serein.Proto.WebSocket/Attributes/AutoSocketModuleAttribute.cs
+++ b/Serein.Proto.WebSocket/Attributes/WebSocketModuleAttribute.cs
@@ -1,8 +1,8 @@
namespace Serein.Proto.WebSocket.Attributes
{
///
- /// 标记该类是处理模板,需要获取WebSocketServer/WebSocketClient了实例后,使用(Server/Client).MsgHandleHelper.AddModule()进行添加。
- /// 处理模板需要继承 ISocketHandleModule 接口,否则WebSocket接受到数据时,将无法进行调用相应的处理模板。
+ /// 标记该类是处理模板
+ /// 处理模板需要继承 ISocketHandleModule 接口,否则接受到 WebSocket 数据时,将无法进行调用相应的处理模板。
/// 使用方式:
/// [AutoSocketModule(ThemeKey = "theme", DataKey = "data")]
/// public class PlcSocketService : ISocketHandleModule
@@ -16,7 +16,7 @@
///
///
[AttributeUsage(AttributeTargets.Class)]
- public sealed class AutoSocketModuleAttribute : Attribute
+ public sealed class WebSocketModuleAttribute : Attribute
{
///
/// 业务标识
diff --git a/Serein.Proto.WebSocket/Attributes/AutoSocketHandleAttribute.cs b/Serein.Proto.WebSocket/Attributes/WsMethodAttribute.cs
similarity index 83%
rename from Serein.Proto.WebSocket/Attributes/AutoSocketHandleAttribute.cs
rename to Serein.Proto.WebSocket/Attributes/WsMethodAttribute.cs
index 96aeadf..f94b0dc 100644
--- a/Serein.Proto.WebSocket/Attributes/AutoSocketHandleAttribute.cs
+++ b/Serein.Proto.WebSocket/Attributes/WsMethodAttribute.cs
@@ -16,7 +16,7 @@
/// Func<dynamic,Task> : 会自动将对象解析为Json字符串,异步发送文本内容。
///
[AttributeUsage(AttributeTargets.Method)]
- public sealed class AutoSocketHandleAttribute : Attribute
+ public sealed class WsMethodAttribute : Attribute
{
///
/// 描述Json业务字段,如果不设置,将默认使用方法名称。
@@ -32,12 +32,6 @@
/// 会进行异步等待,当Task结束后,自动获取TResult进行发送(请避免Task<Task<TResult>>诸如此类的Task泛型嵌套)
///
public bool IsReturnValue = true;
- ///
- /// 表示该方法所有入参不能为空(所需的参数在请求Json的Data不存在)
- /// 若有一个参数无法从data获取,则不会进行调用该方法
- /// 如果设置该属性为 false ,但某些入参不能为空,而不希望在代码中进行检查,请为入参添加[NotNull]/[Needful]特性
- ///
- public bool ArgNotNull = true;
}
diff --git a/Serein.Proto.WebSocket/Handle/Attribute.cs b/Serein.Proto.WebSocket/Handle/Attribute.cs
deleted file mode 100644
index 70275d4..0000000
--- a/Serein.Proto.WebSocket/Handle/Attribute.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace Serein.Proto.WebSocket.Handle
-{
- ///
- /// 表示参数不能为空(Net462不能使用NutNull的情况)
- ///
- public sealed class NeedfulAttribute : Attribute
- {
- }
-
-
-
-}
diff --git a/Serein.Proto.WebSocket/Handle/HandleConfiguration.cs b/Serein.Proto.WebSocket/Handle/MethodInvokeConfiguration.cs
similarity index 78%
rename from Serein.Proto.WebSocket/Handle/HandleConfiguration.cs
rename to Serein.Proto.WebSocket/Handle/MethodInvokeConfiguration.cs
index 1b9c3d8..a1105a3 100644
--- a/Serein.Proto.WebSocket/Handle/HandleConfiguration.cs
+++ b/Serein.Proto.WebSocket/Handle/MethodInvokeConfiguration.cs
@@ -1,4 +1,5 @@
using Serein.Library;
+using static Serein.Proto.WebSocket.SereinWebSocketService;
@@ -8,18 +9,13 @@ namespace Serein.Proto.WebSocket.Handle
/// socket模块处理数据配置
///
- public class HandleConfiguration
+ public class MethodInvokeConfiguration
{
///
/// Emit委托
///
public DelegateDetails? DelegateDetails { get; set; }
- ///
- /// 未捕获的异常跟踪
- ///
- public Action>? OnExceptionTracking { get; set; }
-
///
/// 所使用的实例
///
@@ -30,11 +26,6 @@ namespace Serein.Proto.WebSocket.Handle
///
public bool IsReturnValue { get; set; } = true;
- ///
- /// 是否要求必须不为null
- ///
- public bool ArgNotNull { get; set; } = true;
-
///
/// 是否使用Data整体内容作为入参参数
///
@@ -45,6 +36,21 @@ namespace Serein.Proto.WebSocket.Handle
///
public bool[] UseRequest { get; set; } = [];
+ ///
+ /// 是否需要发送消息的委托
+ ///
+ public bool[] IsNeedSendDelegate { get; set; } = [];
+
+ ///
+ /// 发送消息的委托类型
+ ///
+ public SendType[] SendDelegateType { get; set; } = [];
+
+ ///
+ /// 缓存的发送委托数组
+ ///
+ public Delegate?[] CachedSendDelegates ;
+
///
/// 是否使用消息ID作为入参参数
///
@@ -60,11 +66,6 @@ namespace Serein.Proto.WebSocket.Handle
///
public Type[] ParameterType { get; set; } = [];
- ///
- /// 是否检查变量为空
- ///
- public bool[] IsCheckArgNotNull { get; set; } = [];
-
}
diff --git a/Serein.Proto.WebSocket/Handle/WebSocketHandleModule.cs b/Serein.Proto.WebSocket/Handle/WebSocketHandleModule.cs
index bd0fd29..c86c303 100644
--- a/Serein.Proto.WebSocket/Handle/WebSocketHandleModule.cs
+++ b/Serein.Proto.WebSocket/Handle/WebSocketHandleModule.cs
@@ -1,8 +1,10 @@
using Serein.Library;
+using Serein.Library.Api;
using Serein.Library.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Text.Json.Nodes;
using System.Threading.Tasks;
namespace Serein.Proto.WebSocket.Handle
@@ -16,35 +18,38 @@ namespace Serein.Proto.WebSocket.Handle
///
/// Json消息处理模块
///
- public WebSocketHandleModule(WebSocketHandleModuleConfig config)
+ public WebSocketHandleModule(WebSocketModuleConfig config)
{
- moduleConfig = config;
+ _moduleConfig = config;
+ _methodInvokeConfigs = new ConcurrentDictionary();
+ _myMsgIdHash = new HashSet();
}
///
/// 模块的处理配置
///
- private readonly WebSocketHandleModuleConfig moduleConfig;
+ private readonly WebSocketModuleConfig _moduleConfig;
///
/// 用来判断消息是否重复
///
- private HashSet _myMsgIdHash = new HashSet();
+ private readonly HashSet _myMsgIdHash;
+
///
/// 存储处理数据的配置
///
- public ConcurrentDictionary MyHandleConfigs = new ConcurrentDictionary();
+ private readonly ConcurrentDictionary _methodInvokeConfigs ;
///
/// 添加处理配置
///
/// 处理模块
- internal bool AddHandleConfigs(WebSocketHandleConfiguration config)
+ internal bool AddHandleConfigs(WebSocketMethodConfig config)
{
- if (!MyHandleConfigs.ContainsKey(config.ThemeValue))
+ if (!_methodInvokeConfigs.ContainsKey(config.ThemeValue))
{
- MyHandleConfigs[config.ThemeValue] = config;
+ _methodInvokeConfigs[config.ThemeValue] = config;
return true;
}
else
@@ -60,13 +65,13 @@ namespace Serein.Proto.WebSocket.Handle
///
public bool RemoveConfig(ISocketHandleModule socketControlBase)
{
- foreach (var kv in MyHandleConfigs.ToArray())
+ foreach (var kv in _methodInvokeConfigs.ToArray())
{
var config = kv.Value;
- MyHandleConfigs.TryRemove(kv.Key, out _);
+ _methodInvokeConfigs.TryRemove(kv.Key, out _);
}
- return MyHandleConfigs.Count == 0;
+ return _methodInvokeConfigs.Count == 0;
}
///
@@ -74,8 +79,8 @@ namespace Serein.Proto.WebSocket.Handle
///
public void UnloadConfig()
{
- var temp = MyHandleConfigs.Values;
- MyHandleConfigs.Clear();
+ var temp = _methodInvokeConfigs.Values;
+ _methodInvokeConfigs.Clear();
}
@@ -83,46 +88,64 @@ namespace Serein.Proto.WebSocket.Handle
///
/// 处理JSON数据
///
- public async Task HandleAsync(WebSocketMsgContext context)
+ public async Task HandleAsync(WebSocketHandleContext context)
{
var jsonObject = context.MsgRequest; // 获取到消息
if (jsonObject is null)
{
- // SereinEnv.WriteLine(InfoType.WARN, "没有获取到消息");
+ context.TriggerExceptionTracking($"请求没有获取到消息");
+ return; // 没有获取到消息
+ }
+ if(!jsonObject.TryGetValue(_moduleConfig.ThemeJsonKey, out var themeToken) || themeToken.IsNull)
+ {
+ context.TriggerExceptionTracking($"请求没有获取到主题\"{_moduleConfig.ThemeJsonKey}\"");
+ return; // 没有获取到消息
+ }
+ if(themeToken.Type != IJsonToken.TokenType.Value)
+ {
+ context.TriggerExceptionTracking($"请求主题需要值类型 \"{_moduleConfig.ThemeJsonKey}\"");
return; // 没有获取到消息
}
+ var theme = themeToken.ToString(); // 获取主题
// 验证主题
- if (!jsonObject.TryGetValue(moduleConfig.ThemeJsonKey, out var themeToken)
- || themeToken.ToString() is not string theme
- || !MyHandleConfigs.TryGetValue(theme, out var handldConfig))
+ if (!_methodInvokeConfigs.TryGetValue(theme, out var handldConfig))
{
- // SereinEnv.WriteLine(InfoType.WARN, $"{theme} 主题不存在");
+ context.TriggerExceptionTracking($"{_moduleConfig.ThemeJsonKey} 主题不存在");
return;
}
- // 验证消息ID
- if (!jsonObject.TryGetValue(moduleConfig.MsgIdJsonKey, out var msgIdToken)
- || msgIdToken.ToString() is not string msgId)
+
+ if (!jsonObject.TryGetValue(_moduleConfig.MsgIdJsonKey, out var msgIdToken) || themeToken.IsNull)
{
- // SereinEnv.WriteLine(InfoType.WARN, $"[{msgId}]{theme} 没有消息Id");
- return;
+ context.TriggerExceptionTracking($"主题 {theme} 没有消息Id");
+ return; // 没有获取到消息
+ }
+ if (themeToken.Type != IJsonToken.TokenType.Value)
+ {
+ context.TriggerExceptionTracking($"请求消息Id需要值类型 \"{_moduleConfig.ThemeJsonKey}\"");
+ return; // 没有获取到消息
}
+ var msgId = msgIdToken.ToString(); // 获取主题
// 验证消息ID是否重复
if (!_myMsgIdHash.Add(msgId))
{
- // SereinEnv.WriteLine(InfoType.WARN, $"[{msgId}]{theme} 消息重复");
+ context.TriggerExceptionTracking($"主题 {theme} 消息Id {msgId} 消息重复");
return; // 消息重复
}
// 验证数据
- if (!jsonObject.TryGetValue(moduleConfig.DataJsonKey, out var dataToken))
+ if (!jsonObject.TryGetValue(_moduleConfig.DataJsonKey, out var dataToken))
{
- // SereinEnv.WriteLine(InfoType.WARN, $"[{msgId}]{theme} 消息重复");
+ context.TriggerExceptionTracking($"主题 {theme} 消息Id {msgId} 数据提取失败,当前指定键\"{_moduleConfig.DataJsonKey}\"");
return; // 没有主题
}
+ if(dataToken.Type != IJsonToken.TokenType.Object)
+ {
+ context.TriggerExceptionTracking($"主题 {theme} 消息Id {msgId} 数据需要 JSON Object");
+ }
context.MsgTheme = theme; // 添加主题
context.MsgId = msgId; // 添加 ID
@@ -135,17 +158,17 @@ namespace Serein.Proto.WebSocket.Handle
var result = await HandleAsync(handldConfig, args);
if (handldConfig.IsReturnValue)
{
- await context.RepliedAsync(moduleConfig, context, result);
+ await RepliedAsync(_moduleConfig, context, result);
}
}
else
{
- SereinEnv.WriteLine(InfoType.WARN, $"[{msgId}]{theme} 参数获取失败");
+ context.TriggerExceptionTracking($"主题 {theme} 消息Id {msgId} 参数获取失败");
}
}
catch (Exception ex)
{
- SereinEnv.WriteLine(InfoType.ERROR, $"error in ws : {ex.Message}{Environment.NewLine}json value:{jsonObject}");
+ context.TriggerExceptionTracking(ex);
}
finally
{
@@ -153,6 +176,7 @@ namespace Serein.Proto.WebSocket.Handle
}
}
+
///
/// 调用
@@ -160,7 +184,7 @@ namespace Serein.Proto.WebSocket.Handle
///
///
///
- public static async Task
/// 此次请求的上下文
///
- public void Handle(WebSocketMsgContext context)
+ public async Task HandleAsync(WebSocketMsgContext context)
{
foreach (var module in MyHandleModuleDict.Values)
{
@@ -197,7 +180,7 @@ namespace Serein.Proto.WebSocket.Handle
{
return;
}
- _ = module.HandleAsync(context);
+ await module.HandleAsync(context);
}
diff --git a/Serein.Proto.WebSocket/ISereinWebSocketService.cs b/Serein.Proto.WebSocket/ISereinWebSocketService.cs
new file mode 100644
index 0000000..7377093
--- /dev/null
+++ b/Serein.Proto.WebSocket/ISereinWebSocketService.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using NetWebSocket = System.Net.WebSockets.WebSocket;
+namespace Serein.Proto.WebSocket
+{
+ ///
+ /// WebSocket服务
+ ///
+ public interface ISereinWebSocketService
+ {
+ ///
+ /// 目前有多少个连接
+ ///
+ int ConcetionCount { get; }
+
+ ///
+ /// 添加处理模块
+ ///
+ ///
+ ///
+ ISereinWebSocketService AddHandleModule() where T : ISocketHandleModule, new();
+
+ ///
+ /// 添加处理模块
+ ///
+ ///
+ /// 使用指定的实例
+ ///
+ ISereinWebSocketService AddHandleModule(Func instanceFactory) where T : ISocketHandleModule;
+
+ ///
+ /// 跟踪未处理的异常
+ ///
+ ///
+ ///
+ ISereinWebSocketService TrackUnhandledExceptions(Func, Task> onExceptionTrackingAsync);
+
+ ///
+ /// 添加新的 WebSocket 连接进行处理消息
+ ///
+ ///
+ Task AddWebSocketHandleAsync(NetWebSocket webSocket);
+
+ ///
+ /// 推送消息
+ ///
+ ///
+ ///
+ Task PushDataAsync(object latestData);
+
+ }
+}
diff --git a/Serein.Proto.WebSocket/ISocketHandleModule.cs b/Serein.Proto.WebSocket/ISocketHandleModule.cs
index 26a7ba2..0d368f1 100644
--- a/Serein.Proto.WebSocket/ISocketHandleModule.cs
+++ b/Serein.Proto.WebSocket/ISocketHandleModule.cs
@@ -1,10 +1,7 @@
-using System;
-
-namespace Serein.Proto.WebSocket
+namespace Serein.Proto.WebSocket
{
public interface ISocketHandleModule
{
}
-
}
diff --git a/Serein.Proto.WebSocket/SendType.cs b/Serein.Proto.WebSocket/SendType.cs
new file mode 100644
index 0000000..555af82
--- /dev/null
+++ b/Serein.Proto.WebSocket/SendType.cs
@@ -0,0 +1,30 @@
+namespace Serein.Proto.WebSocket
+{
+public partial class SereinWebSocketService
+ {
+ public enum SendType
+ {
+ ///
+ /// 不发送数据
+ ///
+ None,
+ ///
+ /// 发送字符串
+ ///
+ String,
+ ///
+ /// 发送对象
+ ///
+ Object,
+ ///
+ /// 异步发送字符串
+ ///
+ StringAsync,
+ ///
+ /// 异步发送对象
+ ///
+ ObjectAsync
+ }
+ }
+
+}
diff --git a/Serein.Proto.WebSocket/Serein.Proto.WebSocket.csproj b/Serein.Proto.WebSocket/Serein.Proto.WebSocket.csproj
index dbe2498..14c48d3 100644
--- a/Serein.Proto.WebSocket/Serein.Proto.WebSocket.csproj
+++ b/Serein.Proto.WebSocket/Serein.Proto.WebSocket.csproj
@@ -1,7 +1,7 @@
- net8.0;net462
+ net8.0;
enable
latest
enable
@@ -16,8 +16,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Serein.Proto.WebSocket/SereinWebSocketService.cs b/Serein.Proto.WebSocket/SereinWebSocketService.cs
new file mode 100644
index 0000000..0b1e86c
--- /dev/null
+++ b/Serein.Proto.WebSocket/SereinWebSocketService.cs
@@ -0,0 +1,400 @@
+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 Func, Task> _onExceptionTrackingAsync;
+ ///
+ /// 维护所有 WebSocket 连接
+ ///
+ private readonly List _sockets;
+
+ ///
+ /// 用于增加、移除 WebSocket 连接时,保证线程安全操作
+ ///
+ private readonly object _lock = new object();
+
+ public int ConcetionCount => _sockets.Count;
+
+ 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
+ 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)))
+ {
+ sendType = SendType.ObjectAsync;
+ }
+ else if (type.IsAssignableFrom(typeof(Func)))
+ {
+ sendType = SendType.StringAsync;
+ }
+ else if (type.IsAssignableFrom(typeof(Action)))
+ {
+ sendType = SendType.StringAsync;
+ }
+ else if (type.IsAssignableFrom(typeof(Action)))
+ {
+ sendType = SendType.StringAsync;
+ }
+ else
+ {
+ sendType = SendType.None;
+ return false;
+ }
+ return true;
+ }
+
+ #endregion
+
+ ///
+ /// 跟踪未处理的异常
+ ///
+ ///
+ public ISereinWebSocketService TrackUnhandledExceptions(Func, Task> onExceptionTrackingAsync)
+ {
+ _onExceptionTrackingAsync = onExceptionTrackingAsync;
+ return this;
+ }
+
+
+
+ ///
+ /// 传入新的 WebSocket 连接,开始进行处理
+ ///
+ ///
+
+
+ ///
+ /// 处理新的 WebSocket 连接
+ ///
+ ///
+ ///
+ public async Task AddWebSocketHandleAsync(NetWebSocket socket)
+ {
+ lock (_lock) { _sockets.Add(socket); }
+ var buffer = new byte[4096];
+
+ var msgHandleUtil = new WebSocketMessageTransmissionTool(); // 消息队列
+
+ _ = Task.Run(async () =>
+ {
+ await HandleMsgAsync(socket, msgHandleUtil);
+ });
+
+ try
+ {
+ while (socket.State == WebSocketState.Open)
+ {
+ var result = await socket.ReceiveAsync(buffer: new ArraySegment(buffer), CancellationToken.None);
+ if (result.MessageType == WebSocketMessageType.Close)
+ {
+ break;
+ }
+ else if (result.MessageType == WebSocketMessageType.Text)
+ {
+ var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
+ Console.WriteLine($"收到客户端消息: {message}");
+ var echo = Encoding.UTF8.GetBytes(message);
+ await msgHandleUtil.WriteMsgAsync(message); // 异步传递消息
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"WebSocket 异常: {ex.Message}");
+ }
+ finally
+ {
+ lock (_lock) { _sockets.Remove(socket); }
+ await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "关闭连接", CancellationToken.None);
+ socket.Dispose();
+ }
+ }
+
+ ///
+ /// 处理消息
+ ///
+ ///
+ ///
+ ///
+ private async Task HandleMsgAsync(NetWebSocket webSocket,WebSocketMessageTransmissionTool tranTool)
+ {
+ //var AuthorizedClients = new ConcurrentDictionary();
+ async Task sendasync(string text)
+ {
+ await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入
+ }
+ /*
+ ObjectPool contextPool = new ObjectPool(() =>
+ {
+ return new WebSocketMsgContext(sendasync);
+ }, 20);
+ var context = contextPool.Allocate();
+ contextPool.Free(context);
+ */
+ while (webSocket.State == WebSocketState.Open)
+ {
+ var message = await tranTool.WaitMsgAsync(); // 有消息时通知
+ var context = new WebSocketHandleContext(sendasync);
+ context.MsgRequest = JsonHelper.Parse(message);
+ context.OnExceptionTrackingAsync = _onExceptionTrackingAsync;
+ await HandleAsync(context); // 处理消息
+ }
+
+ }
+
+ ///
+ /// 异步消息
+ ///
+ /// 此次请求的上下文
+ ///
+ private async Task HandleAsync(WebSocketHandleContext context)
+ {
+ foreach (var module in _socketModules.Values)
+ {
+ if (context.Handle)
+ {
+ return;
+ }
+ await module.HandleAsync(context);
+ }
+
+
+ }
+
+ ///
+ /// 给所有客户端广播最新数据
+ ///
+ ///
+ ///
+ public async Task PushDataAsync(object latestData)
+ {
+ var options = new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ };
+ var json = JsonSerializer.Serialize(latestData, options);
+ var buffer = Encoding.UTF8.GetBytes(json);
+ var segment = new ArraySegment(buffer);
+
+ List socketsCopy;
+ lock (_lock)
+ {
+ socketsCopy = _sockets.ToList();
+ }
+
+ foreach (var socket in socketsCopy)
+ {
+ if (socket.State == WebSocketState.Open)
+ {
+ try
+ {
+ await socket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
+ }
+ catch
+ {
+ // 忽略异常或移除失效连接
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/Serein.Proto.WebSocket/SocketExtension.cs b/Serein.Proto.WebSocket/SocketExtension.cs
new file mode 100644
index 0000000..aec6877
--- /dev/null
+++ b/Serein.Proto.WebSocket/SocketExtension.cs
@@ -0,0 +1,29 @@
+using Serein.Library.Utils;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.WebSockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+using NetWebSocket = System.Net.WebSockets.WebSocket;
+namespace Serein.Proto.WebSocket
+{
+
+ public class SocketExtension
+ {
+ ///
+ /// 发送消息
+ ///
+ ///
+ ///
+ ///
+ public static async Task SendAsync(NetWebSocket webSocket, string message)
+ {
+ var buffer = Encoding.UTF8.GetBytes(message);
+ await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
+ }
+ }
+}
diff --git a/Serein.Proto.WebSocket/TestClass.cs b/Serein.Proto.WebSocket/TestClass.cs
new file mode 100644
index 0000000..654a27f
--- /dev/null
+++ b/Serein.Proto.WebSocket/TestClass.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Proto.WebSocket
+{
+
+ public class ClassA : ISocketHandleModule
+ {
+
+ }
+ public class ClassB : ISocketHandleModule
+ {
+
+ }
+ public class ClassC : ISocketHandleModule
+ {
+
+ }
+ internal class TestClass
+ {
+ public void Run()
+ {
+ SereinWebSocketService sereinWebSocketService = new SereinWebSocketService();
+ sereinWebSocketService.AddHandleModule();
+ sereinWebSocketService.AddHandleModule(() => new ClassB());
+ sereinWebSocketService.TrackUnhandledExceptions(OnExceptionTrackingAsync);
+ }
+
+ private static async Task OnExceptionTrackingAsync(Exception ex, Func SendAsync)
+ {
+ await SendAsync("");
+ }
+ }
+}
diff --git a/Serein.Proto.WebSocket/WebSocketClient.cs b/Serein.Proto.WebSocket/WebSocketClient.cs
index f86bdce..951be18 100644
--- a/Serein.Proto.WebSocket/WebSocketClient.cs
+++ b/Serein.Proto.WebSocket/WebSocketClient.cs
@@ -6,6 +6,7 @@ using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using NetWebSocket = System.Net.WebSockets.WebSocket;
namespace Serein.Proto.WebSocket
{
@@ -50,6 +51,7 @@ namespace Serein.Proto.WebSocket
}
}
+
///
/// 发送消息
///
@@ -67,7 +69,7 @@ namespace Serein.Proto.WebSocket
private async Task ReceiveAsync()
{
- var msgQueueUtil = new MsgHandleUtil();
+ var msgQueueUtil = new WebSocketMessageTransmissionTool();
_ = Task.Run(async () =>
{
await HandleMsgAsync(_client, msgQueueUtil);
@@ -100,12 +102,6 @@ namespace Serein.Proto.WebSocket
{
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
}
- //else
- //{
- // var completeMessage = receivedMessage.ToString();
- // MsgHandleHelper.HandleMsg(SendAsync, completeMessage); // 处理消息,如果方法入参是需要发送消息委托时,将 SendAsync 作为委托参数提供
- // //Debug.WriteLine($"Received: {completeMessage}");
- //}
}
@@ -116,8 +112,13 @@ namespace Serein.Proto.WebSocket
}
}
-
- public async Task HandleMsgAsync(System.Net.WebSockets.WebSocket webSocket, MsgHandleUtil msgQueueUtil)
+ ///
+ /// 处理消息
+ ///
+ ///
+ ///
+ ///
+ public async Task HandleMsgAsync(NetWebSocket webSocket, WebSocketMessageTransmissionTool msgQueueUtil)
{
async Task sendasync(string text)
{
@@ -128,87 +129,8 @@ namespace Serein.Proto.WebSocket
var message = await msgQueueUtil.WaitMsgAsync(); // 有消息时通知
var context = new WebSocketMsgContext(sendasync);
context.MsgRequest = JsonHelper.Parse(message);
- MsgHandleHelper.Handle(context); // 处理消息
-
- //using (var context = new WebSocketMsgContext(sendasync))
- //{
- // context.JsonObject = JObject.Parse(message);
- // await MsgHandleHelper.HandleAsync(context); // 处理消息
- //}
-
- //_ = Task.Run(() => {
- // JObject json = JObject.Parse(message);
- // WebSocketMsgContext context = new WebSocketMsgContext(async (text) =>
- // {
- // await SocketExtension.SendAsync(webSocket, text); // 回复客户端,处理方法中入参如果需要发送消息委托,则将该回调方法作为委托参数传入
- // });
- // context.JsonObject = json;
- // await MsgHandleHelper.HandleAsync(context); // 处理消息
- //});
-
+ MsgHandleHelper.HandleAsync(context); // 处理消息
}
-
-
- /* #region 消息处理
- private readonly string ThemeField;
- private readonly ConcurrentDictionary ThemeConfigs = new ConcurrentDictionary();
-
- public async Task HandleSocketMsg(string jsonStr)
- {
- JObject json;
- try
- {
- json = JObject.Parse(jsonStr);
- }
- catch (Exception ex)
- {
- await SendAsync(_client, ex.Message);
- return;
- }
- // 获取到消息
- string themeName = json[ThemeField]?.ToString();
- if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
- {
- return;
- }
-
- object dataValue;
- if (string.IsNullOrEmpty(handldConfig.DataField))
- {
- dataValue = json.ToObject(handldConfig.DataType);
- }
- else
- {
- dataValue = json[handldConfig.DataField].ToObject(handldConfig.DataType);
- }
- await handldConfig.Invoke(dataValue, SendAsync);
- }
-
- public void AddConfig(string themeName, Type dataType, MsgHandler msgHandler)
- {
- if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
- {
- handldConfig = new HandldConfig
- {
- DataField = themeName,
- DataType = dataType
- };
- ThemeConfigs.TryAdd(themeName, handldConfig);
- }
- handldConfig.HandldAsync += msgHandler;
- }
- public void RemoteConfig(string themeName, MsgHandler msgHandler)
- {
- if (ThemeConfigs.TryGetValue(themeName, out var handldConfig))
- {
- handldConfig.HandldAsync -= msgHandler;
- if (!handldConfig.HasSubscribers)
- {
- ThemeConfigs.TryRemove(themeName, out _);
- }
- }
- }
- #endregion*/
}
}
}
diff --git a/Serein.Proto.WebSocket/Handle/WebSocketMsgContext.cs b/Serein.Proto.WebSocket/WebSocketHandleContext.cs
similarity index 52%
rename from Serein.Proto.WebSocket/Handle/WebSocketMsgContext.cs
rename to Serein.Proto.WebSocket/WebSocketHandleContext.cs
index acb8407..ebdb58b 100644
--- a/Serein.Proto.WebSocket/Handle/WebSocketMsgContext.cs
+++ b/Serein.Proto.WebSocket/WebSocketHandleContext.cs
@@ -1,21 +1,29 @@
using Serein.Library.Api;
using Serein.Library.Utils;
+using Serein.Proto.WebSocket.Handle;
using System;
using System.Threading.Tasks;
-namespace Serein.Proto.WebSocket.Handle
+namespace Serein.Proto.WebSocket
{
///
/// 消息处理上下文
///
- public class WebSocketMsgContext : IDisposable
+ public class WebSocketHandleContext : IDisposable
{
- public WebSocketMsgContext(Func sendAsync)
+ ///
+ /// 构造函数,传入发送消息的异步方法
+ ///
+ ///
+ public WebSocketHandleContext(Func sendAsync)
{
_sendAsync = sendAsync;
}
+ ///
+ /// 释放资源,清理消息上下文
+ ///
public void Dispose()
{
MsgRequest = null;
@@ -23,7 +31,6 @@ namespace Serein.Proto.WebSocket.Handle
MsgId = string.Empty;
MsgData = null;
MsgData = null;
- _sendAsync = null;
}
///
@@ -37,7 +44,8 @@ namespace Serein.Proto.WebSocket.Handle
}
} }
- public bool _handle = false;
+ private bool _handle = false;
+
///
/// 消息本体(IJsonToken)
@@ -59,8 +67,16 @@ namespace Serein.Proto.WebSocket.Handle
///
public IJsonToken? MsgData { get; set; }
+ ///
+ /// 异常外部感知使能
+ ///
+ public Func, Task> OnExceptionTrackingAsync { get; set; }
- private Func? _sendAsync;
+ ///
+ /// 发送消息
+ ///
+
+ private Func _sendAsync;
///
/// 发送消息
@@ -69,48 +85,40 @@ namespace Serein.Proto.WebSocket.Handle
///
public async Task SendAsync(string msg)
{
- if (_sendAsync is null) return;
await _sendAsync.Invoke(msg);
}
-
///
- /// 返回消息
+ /// 触发异常追踪
///
- ///
- ///
- ///
- ///
- public async Task RepliedAsync(WebSocketHandleModuleConfig moduleConfig,
- WebSocketMsgContext context,
- object data)
+ public void TriggerExceptionTracking(string exMessage)
{
- if (moduleConfig.IsResponseUseReturn)
+ var ex = new Exception(exMessage);
+ Func func = async (data) =>
{
- var responseContent = JsonHelper.Serialize(data);
- await SendAsync(responseContent);
- }
- else
+ var msg = JsonHelper.Serialize(data);
+ await _sendAsync.Invoke(msg);
+
+ };
+ OnExceptionTrackingAsync.Invoke(ex, func);
+ }
+
+ ///
+ /// 触发异常追踪
+ ///
+ public void TriggerExceptionTracking(Exception ex)
+ {
+ Func func = async (data) =>
{
+ var msg = JsonHelper.Serialize(data);
+ await _sendAsync.Invoke(msg);
- IJsonToken jsonData;
-
- jsonData = JsonHelper.Object(obj =>
- {
- obj[moduleConfig.MsgIdJsonKey] = context.MsgId;
- obj[moduleConfig.ThemeJsonKey] = context.MsgTheme;
- obj[moduleConfig.DataJsonKey] = data is null ? null
- : JsonHelper.FromObject(data);
- });
-
- var msg = jsonData.ToString();
- //Console.WriteLine($"[{msgId}] => {theme}");
- await SendAsync(msg);
- }
-
+ };
+ OnExceptionTrackingAsync.Invoke(ex, func);
}
-
+
+
}
}
diff --git a/Serein.Proto.WebSocket/TestExtension.cs b/Serein.Proto.WebSocket/WebSocketMessageTransmissionTool.cs
similarity index 59%
rename from Serein.Proto.WebSocket/TestExtension.cs
rename to Serein.Proto.WebSocket/WebSocketMessageTransmissionTool.cs
index a12effc..0a358da 100644
--- a/Serein.Proto.WebSocket/TestExtension.cs
+++ b/Serein.Proto.WebSocket/WebSocketMessageTransmissionTool.cs
@@ -1,28 +1,15 @@
-using Serein.Library.Utils;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net.WebSockets;
-using System.Text;
-using System.Threading;
-using System.Threading.Channels;
-using System.Threading.Tasks;
+using System.Threading.Channels;
namespace Serein.Proto.WebSocket
{
///
/// 消息处理工具
///
- public class MsgHandleUtil
+ public class WebSocketMessageTransmissionTool
{
private readonly Channel _msgChannel;
- ///
- /// 初始化优先容器
- ///
- ///
- public MsgHandleUtil(int capacity = 100)
+ public WebSocketMessageTransmissionTool(int capacity = 100)
{
_msgChannel = Channel.CreateBounded(new BoundedChannelOptions(capacity)
{
@@ -72,22 +59,4 @@ namespace Serein.Proto.WebSocket
_msgChannel.Writer.Complete();
}
}
-
-
-
-
- public class SocketExtension
- {
- ///
- /// 发送消息
- ///
- ///
- ///
- ///
- public static async Task SendAsync(System.Net.WebSockets.WebSocket webSocket, string message)
- {
- var buffer = Encoding.UTF8.GetBytes(message);
- await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
- }
- }
}
diff --git a/Serein.Proto.WebSocket/WebSocketServer.cs b/Serein.Proto.WebSocket/WebSocketServer.cs
index b06b4fa..bc5b16e 100644
--- a/Serein.Proto.WebSocket/WebSocketServer.cs
+++ b/Serein.Proto.WebSocket/WebSocketServer.cs
@@ -189,7 +189,7 @@ namespace Serein.Proto.WebSocket
return;
}
- var msgQueueUtil = new MsgHandleUtil();
+ var msgQueueUtil = new WebSocketMessageTransmissionTool();
_ = Task.Run(async () =>
{
await HandleMsgAsync(webSocket,msgQueueUtil, authorizedHelper);
@@ -240,7 +240,7 @@ namespace Serein.Proto.WebSocket
public async Task HandleMsgAsync(System.Net.WebSockets.WebSocket webSocket,
- MsgHandleUtil msgQueueUtil,
+ WebSocketMessageTransmissionTool msgQueueUtil,
WebSocketAuthorizedHelper authorizedHelper)
{
async Task sendasync(string text)
@@ -265,7 +265,7 @@ namespace Serein.Proto.WebSocket
}
var context = new WebSocketMsgContext(sendasync);
context.MsgRequest = JsonHelper.Parse(message);
- MsgHandleHelper.Handle(context); // 处理消息
+ MsgHandleHelper.HandleAsync(context); // 处理消息
//using (var context = new WebSocketMsgContext(sendasync))
//{
diff --git a/Workbench/App.xaml.cs b/Workbench/App.xaml.cs
index ea53be4..e3ce229 100644
--- a/Workbench/App.xaml.cs
+++ b/Workbench/App.xaml.cs
@@ -51,7 +51,7 @@ namespace Serein.Workbench
private void Application_Startup(object sender, StartupEventArgs e)
{
-#if DEBUG && true
+#if DEBUG && false
try
{
diff --git a/Workbench/Test.cs b/Workbench/Test.cs
new file mode 100644
index 0000000..b2fa14c
--- /dev/null
+++ b/Workbench/Test.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Workbench
+{
+ internal class Test
+ {
+ }
+}