From 89eda9ec4e12f79a6e8e729830ee73c9891d7063 Mon Sep 17 00:00:00 2001 From: hyh Date: Mon, 16 Jun 2025 16:29:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=A4=84=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CoreAgent.Domain/CoreAgent.Domain.csproj | 6 + CoreAgent.Domain/Helpers/JsonHelper.cs | 48 +++ .../CustomWSClient/ICustomMessageHandler.cs | 13 + .../IObserverCustomWebSocketClient.cs | 13 + .../Network/ICellularNetworkContext.cs | 6 + .../IProtocolLogsProviderObserver.cs | 13 + .../IProtocollHandleLogs.cs | 15 + .../Models/Protocol/BaseNetworkLog.cs | 55 +++ .../Models/Protocol/ImsLayerLog.cs | 80 ++++ CoreAgent.Domain/Models/Protocol/LogLevel.cs | 27 ++ .../Models/Protocol/NetworkLayerLogs.cs | 54 +++ .../Models/Protocol/ProtocolLog.cs | 97 +++++ .../Models/Protocol/ProtocolLogDetail.cs | 76 ++++ .../Models/Protocol/RanLayerLog.cs | 136 +++++++ .../Contexts/CellularNetworkContext.cs | 9 + .../CoreAgent.Infrastructure.csproj | 2 + .../CustomWSClient/CustomWebSocketClient.cs | 172 ++++++++ .../ObserverCustomWebSocketClient.cs | 143 +++++++ .../IMSLogMessageHandler.cs | 264 +++++++++++++ .../ProtocolLogsProviderObserver.cs | 147 +++++++ .../ProtocolMSHandleLogs.cs | 30 ++ .../ProtocolMSParesHandleLogs.cs | 12 + .../ProtocolParesHandleLogs.cs | 41 ++ .../ProtocolRanHandleLogs.cs | 30 ++ .../ProtocolRanParesHandleLogs.cs.cs | 284 ++++++++++++++ .../RanLogMessageHandler.cs | 368 ++++++++++++++++++ 26 files changed, 2141 insertions(+) create mode 100644 CoreAgent.Domain/Helpers/JsonHelper.cs create mode 100644 CoreAgent.Domain/Interfaces/CustomWSClient/ICustomMessageHandler.cs create mode 100644 CoreAgent.Domain/Interfaces/CustomWSClient/IObserverCustomWebSocketClient.cs create mode 100644 CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocolLogsProviderObserver.cs create mode 100644 CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocollHandleLogs.cs create mode 100644 CoreAgent.Domain/Models/Protocol/BaseNetworkLog.cs create mode 100644 CoreAgent.Domain/Models/Protocol/ImsLayerLog.cs create mode 100644 CoreAgent.Domain/Models/Protocol/LogLevel.cs create mode 100644 CoreAgent.Domain/Models/Protocol/NetworkLayerLogs.cs create mode 100644 CoreAgent.Domain/Models/Protocol/ProtocolLog.cs create mode 100644 CoreAgent.Domain/Models/Protocol/ProtocolLogDetail.cs create mode 100644 CoreAgent.Domain/Models/Protocol/RanLayerLog.cs create mode 100644 CoreAgent.Infrastructure/Services/CustomWSClient/CustomWebSocketClient.cs create mode 100644 CoreAgent.Infrastructure/Services/CustomWSClient/ObserverCustomWebSocketClient.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/IMSLogMessageHandler.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolLogsProviderObserver.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSHandleLogs.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSParesHandleLogs.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolParesHandleLogs.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanHandleLogs.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanParesHandleLogs.cs.cs create mode 100644 CoreAgent.Infrastructure/Services/ProtocolLogHandlers/RanLogMessageHandler.cs diff --git a/CoreAgent.Domain/CoreAgent.Domain.csproj b/CoreAgent.Domain/CoreAgent.Domain.csproj index 0ef5678..85110c7 100644 --- a/CoreAgent.Domain/CoreAgent.Domain.csproj +++ b/CoreAgent.Domain/CoreAgent.Domain.csproj @@ -6,6 +6,12 @@ enable + + + + + + diff --git a/CoreAgent.Domain/Helpers/JsonHelper.cs b/CoreAgent.Domain/Helpers/JsonHelper.cs new file mode 100644 index 0000000..c25c414 --- /dev/null +++ b/CoreAgent.Domain/Helpers/JsonHelper.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Domain.Helpers +{ + public static class JsonHelper + { + /// + /// 对象序列化 + /// + /// 对象 + /// 是否使用textjson + /// 返回json字符串 + public static string ObjToJson(this object obj, bool isUseTextJson = false) + { + if (isUseTextJson) + { + return System.Text.Json.JsonSerializer.Serialize(obj); + } + else + { + return Newtonsoft.Json.JsonConvert.SerializeObject(obj); + } + } + + /// + /// json反序列化obj + /// + /// 反序列类型 + /// json + /// 是否使用textjson + /// 返回对象 + public static T JsonToObj(this string strJson, bool isUseTextJson = false) + { + if (isUseTextJson) + { + return System.Text.Json.JsonSerializer.Deserialize(strJson); + } + else + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(strJson); + } + } + } +} diff --git a/CoreAgent.Domain/Interfaces/CustomWSClient/ICustomMessageHandler.cs b/CoreAgent.Domain/Interfaces/CustomWSClient/ICustomMessageHandler.cs new file mode 100644 index 0000000..ac57127 --- /dev/null +++ b/CoreAgent.Domain/Interfaces/CustomWSClient/ICustomMessageHandler.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Domain.Interfaces.CustomWSClient +{ + public interface ICustomMessageHandler + { + void HandleMessage(string MsgData, IObserverCustomWebSocketClient observer); + } +} diff --git a/CoreAgent.Domain/Interfaces/CustomWSClient/IObserverCustomWebSocketClient.cs b/CoreAgent.Domain/Interfaces/CustomWSClient/IObserverCustomWebSocketClient.cs new file mode 100644 index 0000000..0fdef65 --- /dev/null +++ b/CoreAgent.Domain/Interfaces/CustomWSClient/IObserverCustomWebSocketClient.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Domain.Interfaces.CustomWSClient +{ + public interface IObserverCustomWebSocketClient + { + public void SendMessage(string message); + } +} diff --git a/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs b/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs index f0ff768..06145e7 100644 --- a/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs +++ b/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs @@ -1,4 +1,5 @@ using CoreAgent.Domain.Models.Network; +using CoreAgent.Domain.Models.Protocol; using CoreAgent.Domain.Models.System; namespace CoreAgent.Domain.Interfaces.Network; @@ -30,6 +31,11 @@ public interface ICellularNetworkContext /// NetworkConfigType CurrentConfigType { get; } + /// + /// 网络层日志配置 + /// + NetworkLayerLogs NetworkLogs { get; } + #endregion #region 生命周期管理 diff --git a/CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocolLogsProviderObserver.cs b/CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocolLogsProviderObserver.cs new file mode 100644 index 0000000..7fd4d21 --- /dev/null +++ b/CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocolLogsProviderObserver.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Domain.Interfaces.ProtocolLogHandlers +{ + public interface IProtocolLogsProviderObserver + { + void OnData(string msg); + } +} diff --git a/CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocollHandleLogs.cs b/CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocollHandleLogs.cs new file mode 100644 index 0000000..df0a354 --- /dev/null +++ b/CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocollHandleLogs.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Domain.Interfaces.ProtocolLogHandlers +{ + public interface IProtocollHandleLogs + { + public void RunStart(); + + public void RunStop(); + } +} diff --git a/CoreAgent.Domain/Models/Protocol/BaseNetworkLog.cs b/CoreAgent.Domain/Models/Protocol/BaseNetworkLog.cs new file mode 100644 index 0000000..0f2d285 --- /dev/null +++ b/CoreAgent.Domain/Models/Protocol/BaseNetworkLog.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; +using System; +using System.Text.Json.Serialization; + +namespace CoreAgent.Domain.Models.Protocol; + +/// +/// 基础网络日志实体类 +/// 提供网络日志的通用属性和配置 +/// +/// 日志层类型(如ImsLayerLog或RanLayerLog) +public class BaseNetworkLog +{ + /// + /// 超时时间(毫秒) + /// + [JsonProperty("timeout")] + public int Timeout { get; set; } + + /// + /// 最小日志数量 + /// + [JsonProperty("min")] + public int MinLogCount { get; set; } + + /// + /// 最大日志数量 + /// + [JsonProperty("max")] + public int MaxLogCount { get; set; } + + /// + /// 日志层配置 + /// + [JsonProperty("layers")] + public T LayerConfig { get; set; } + + /// + /// 日志消息 + /// + [JsonProperty("message")] + public string Message { get; set; } + + /// + /// 是否包含消息头 + /// + [JsonProperty("headers")] + public bool IncludeHeaders { get; set; } + + /// + /// 消息ID + /// + [JsonProperty("message_id")] + public int MessageId { get; set; } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Protocol/ImsLayerLog.cs b/CoreAgent.Domain/Models/Protocol/ImsLayerLog.cs new file mode 100644 index 0000000..f2cd466 --- /dev/null +++ b/CoreAgent.Domain/Models/Protocol/ImsLayerLog.cs @@ -0,0 +1,80 @@ +using System; +using System.Text.Json.Serialization; + +namespace CoreAgent.Domain.Models.Protocol; + +/// +/// IMS层日志实体类 +/// 该实体用于记录IMS(IP多媒体子系统)相关的各层日志信息 +/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分 +/// +public class ImsLayerLog +{ + /// + /// CX协议层日志级别 + /// + public string CX { get; set; } + + /// + /// IMS协议层日志级别 + /// + public string IMS { get; set; } + + /// + /// IPSEC协议层日志级别 + /// + public string IPSEC { get; set; } + + /// + /// MEDIA协议层日志级别 + /// + public string MEDIA { get; set; } + + /// + /// MMS协议层日志级别 + /// + public string MMS { get; set; } + + /// + /// RX协议层日志级别 + /// + public string RX { get; set; } + + /// + /// SIP协议层日志级别 + /// + public string SIP { get; set; } + + /// + /// 初始化IMS层日志级别 + /// + public void InitializeLogLevels() + { + CX = LogLevel.Warn.ToString().ToLower(); + IMS = LogLevel.Warn.ToString().ToLower(); + IPSEC = LogLevel.Warn.ToString().ToLower(); + MEDIA = LogLevel.Warn.ToString().ToLower(); + MMS = LogLevel.Warn.ToString().ToLower(); + RX = LogLevel.Warn.ToString().ToLower(); + SIP = LogLevel.Debug.ToString().ToLower(); + } + + /// + /// 更新指定层的日志级别 + /// + /// 层名称 + /// 日志级别 + /// 是否更新成功 + public bool UpdateLogLevel(string layerName, LogLevel logLevel) + { + if (string.IsNullOrEmpty(layerName)) + return false; + + var property = GetType().GetProperty(layerName); + if (property == null) + return false; + + property.SetValue(this, logLevel.ToString().ToLower()); + return true; + } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Protocol/LogLevel.cs b/CoreAgent.Domain/Models/Protocol/LogLevel.cs new file mode 100644 index 0000000..5a7abfd --- /dev/null +++ b/CoreAgent.Domain/Models/Protocol/LogLevel.cs @@ -0,0 +1,27 @@ +namespace CoreAgent.Domain.Models.Protocol; + +/// +/// 日志级别枚举 +/// +public enum LogLevel +{ + /// + /// 调试级别 + /// + Debug, + + /// + /// 信息级别 + /// + Info, + + /// + /// 警告级别 + /// + Warn, + + /// + /// 错误级别 + /// + Error +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Protocol/NetworkLayerLogs.cs b/CoreAgent.Domain/Models/Protocol/NetworkLayerLogs.cs new file mode 100644 index 0000000..158a238 --- /dev/null +++ b/CoreAgent.Domain/Models/Protocol/NetworkLayerLogs.cs @@ -0,0 +1,54 @@ +using System; +using System.Text.Json.Serialization; + +namespace CoreAgent.Domain.Models.Protocol; + +/// +/// 网络层日志集合 +/// 用于统一管理不同网络层的日志配置 +/// +public class NetworkLayerLogs +{ + /// + /// IMS层日志配置 + /// + public ImsLayerLog ImsLog { get; set; } + + /// + /// RAN层日志配置 + /// + public RanLayerLog RanLog { get; set; } + + /// + /// 初始化所有网络层的日志级别 + /// + /// 是否为非独立组网模式(NSA模式) + public void InitializeAllLogLevels(bool isNonStandaloneMode = false) + { + ImsLog = new ImsLayerLog(); + RanLog = new RanLayerLog(); + + ImsLog.InitializeLogLevels(); + RanLog.InitializeLogLevels(isNonStandaloneMode); + } + + /// + /// 更新指定网络层和指定层的日志级别 + /// + /// 网络类型("IMS" 或 "RAN") + /// 层名称 + /// 日志级别 + /// 是否更新成功 + public bool UpdateLogLevel(string networkType, string layerName, LogLevel logLevel) + { + if (string.IsNullOrEmpty(networkType) || string.IsNullOrEmpty(layerName)) + return false; + + return networkType.ToUpper() switch + { + "IMS" => ImsLog?.UpdateLogLevel(layerName, logLevel) ?? false, + "RAN" => RanLog?.UpdateLogLevel(layerName, logLevel) ?? false, + _ => false + }; + } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Protocol/ProtocolLog.cs b/CoreAgent.Domain/Models/Protocol/ProtocolLog.cs new file mode 100644 index 0000000..4c05e6b --- /dev/null +++ b/CoreAgent.Domain/Models/Protocol/ProtocolLog.cs @@ -0,0 +1,97 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; + +namespace CoreAgent.Domain.Models.Protocol; + +/// +/// 协议日志实体类 +/// +public record class ProtocolLog +{ + /// + /// 消息ID + /// + [JsonProperty("message_id")] + public int? MessageId { get; set; } + + /// + /// 消息头信息 + /// + [JsonProperty("headers")] + public string[]? Headers { get; set; } + + /// + /// 消息内容 + /// + [JsonProperty("message")] + public string Message { get; set; } + + /// + /// 消息类型 + /// + [JsonProperty("type")] + public string? Type { get; set; } + + /// + /// 消息名称 + /// + [JsonProperty("name")] + public string? Name { get; set; } + + /// + /// 协议版本 + /// + [JsonProperty("version")] + public string? Version { get; set; } + + /// + /// 时间戳 + /// + [JsonProperty("time")] + public double? Time { get; set; } + + /// + /// UTC时间戳 + /// + [JsonProperty("utc")] + public double? Utc { get; set; } + + /// + /// 日志明细 + /// + [JsonProperty("logs")] + public JToken? Logs { get; set; } + + /// + /// 初始化协议日志实体类的新实例 + /// + /// 消息内容 + /// 消息类型 + /// 协议版本 + /// 时间戳 + /// UTC时间戳 + /// 日志明细 + /// 消息ID + /// 消息头信息 + public ProtocolLog( + string message, + string? type, + string? version, + double? time, + double? utc, + JToken? logs, + int? messageId, + string[]? headers) + { + Message = message; + Type = type; + Version = version; + Name = type; + Utc = utc; + Time = time; + Logs = logs; + MessageId = messageId ?? 0; + Headers = headers; + } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Protocol/ProtocolLogDetail.cs b/CoreAgent.Domain/Models/Protocol/ProtocolLogDetail.cs new file mode 100644 index 0000000..20e59af --- /dev/null +++ b/CoreAgent.Domain/Models/Protocol/ProtocolLogDetail.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace CoreAgent.Domain.Models.Protocol; + +/// +/// 协议日志明细 +/// +public class ProtocolLogDetail +{ + /// + /// 源信息 + /// + [JsonProperty("src")] + public string Src { get; set; } + + /// + /// 索引 + /// + [JsonProperty("idx")] + public int Idx { get; set; } + + /// + /// 日志级别 + /// + [JsonProperty("level")] + public int Level { get; set; } + + /// + /// 方向 + /// + [JsonProperty("dir")] + public string Dir { get; set; } + + /// + /// 时间戳 + /// + [JsonProperty("timestamp")] + public long Timestamp { get; set; } + + /// + /// 小区信息 + /// + [JsonProperty("cell")] + public int? Cell { get; set; } + + /// + /// 数据列表 + /// + [JsonProperty("data")] + public List Data { get; set; } + + /// + /// 层信息 + /// + [JsonProperty("layer")] + public string Layer { get; set; } + + /// + /// UE标识 + /// + [JsonProperty("ue_id")] + public int? UeId { get; set; } + + /// + /// 帧信息 + /// + [JsonProperty("frame")] + public int? Frame { get; set; } + + /// + /// 时隙信息 + /// + [JsonProperty("slot")] + public int? Slot { get; set; } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Protocol/RanLayerLog.cs b/CoreAgent.Domain/Models/Protocol/RanLayerLog.cs new file mode 100644 index 0000000..1ad1803 --- /dev/null +++ b/CoreAgent.Domain/Models/Protocol/RanLayerLog.cs @@ -0,0 +1,136 @@ +using System; +using System.Text.Json.Serialization; + +namespace CoreAgent.Domain.Models.Protocol; + +/// +/// RAN层日志实体类 +/// 该实体用于记录RAN(无线接入网)相关的各层日志信息 +/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分 +/// +public class RanLayerLog +{ + /// + /// GTP-U协议层日志级别 + /// + public string GTPU { get; set; } + + /// + /// LPPa协议层日志级别 + /// + public string LPPa { get; set; } + + /// + /// M2AP协议层日志级别 + /// + public string M2AP { get; set; } + + /// + /// MAC协议层日志级别 + /// + public string MAC { get; set; } + + /// + /// NAS协议层日志级别 + /// + public string NAS { get; set; } + + /// + /// NGAP协议层日志级别 + /// + public string NGAP { get; set; } + + /// + /// NRPPa协议层日志级别 + /// + public string NRPPa { get; set; } + + /// + /// PDCP协议层日志级别 + /// + public string PDCP { get; set; } + + /// + /// PHY协议层日志级别 + /// + public string PHY { get; set; } + + /// + /// RLC协议层日志级别 + /// + public string RLC { get; set; } + + /// + /// RRC协议层日志级别 + /// + public string RRC { get; set; } + + /// + /// S1AP协议层日志级别 + /// + public string S1AP { get; set; } + + /// + /// TRX协议层日志级别 + /// + public string TRX { get; set; } + + /// + /// X2AP协议层日志级别 + /// + public string X2AP { get; set; } + + /// + /// XnAP协议层日志级别 + /// + public string XnAP { get; set; } + + /// + /// PROD协议层日志级别 + /// + [JsonIgnore] + public string PROD { get; set; } + + /// + /// 初始化RAN层日志级别 + /// + /// 是否为非独立组网模式(NSA模式) + public void InitializeLogLevels(bool isNonStandaloneMode = false) + { + GTPU = LogLevel.Warn.ToString().ToLower(); + LPPa = LogLevel.Warn.ToString().ToLower(); + M2AP = LogLevel.Warn.ToString().ToLower(); + MAC = LogLevel.Warn.ToString().ToLower(); + NAS = LogLevel.Warn.ToString().ToLower(); + NGAP = LogLevel.Warn.ToString().ToLower(); + NRPPa = LogLevel.Warn.ToString().ToLower(); + PDCP = LogLevel.Warn.ToString().ToLower(); + PHY = LogLevel.Warn.ToString().ToLower(); + RLC = LogLevel.Warn.ToString().ToLower(); + RRC = LogLevel.Warn.ToString().ToLower(); + S1AP = LogLevel.Warn.ToString().ToLower(); + TRX = LogLevel.Warn.ToString().ToLower(); + X2AP = LogLevel.Warn.ToString().ToLower(); + XnAP = LogLevel.Warn.ToString().ToLower(); + PROD = LogLevel.Warn.ToString().ToLower(); + } + + /// + /// 更新指定层的日志级别 + /// + /// 层名称 + /// 日志级别 + /// 是否更新成功 + public bool UpdateLogLevel(string layerName, LogLevel logLevel) + { + if (string.IsNullOrEmpty(layerName)) + return false; + + var property = GetType().GetProperty(layerName); + if (property == null) + return false; + + property.SetValue(this, logLevel.ToString().ToLower()); + return true; + } +} \ No newline at end of file diff --git a/CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs b/CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs index 094ce68..89dbe64 100644 --- a/CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs +++ b/CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs @@ -4,6 +4,7 @@ using CoreAgent.Domain.Models.Network; using CoreAgent.Domain.Models.System; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; +using CoreAgent.Domain.Models.Protocol; namespace CoreAgent.Infrastructure.Contexts; @@ -23,6 +24,7 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable private readonly INetworkIPEndPointManager _networkIPEndPointManager; private NetworkConfigType _currentConfigType; private readonly ILogger _logger; + private NetworkLayerLogs _networkLogs; /// /// 获取取消令牌源 @@ -44,6 +46,11 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable /// public NetworkConfigType CurrentConfigType => _currentConfigType; + /// + /// 网络层日志配置 + /// + public NetworkLayerLogs NetworkLogs => _networkLogs; + public CellularNetworkContext( IOptions networkCommandConfig, IOptions appSettings, @@ -58,6 +65,7 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable _networkIPEndPointManager = networkIPEndPointManager ?? throw new ArgumentNullException(nameof(networkIPEndPointManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _currentConfigType = NetworkConfigType.None; + _networkLogs = new NetworkLayerLogs(); } /// @@ -249,6 +257,7 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable _networkState = new CellularNetworkState(string.Empty); _networkIPEndPointManager.Clear(); _currentConfigType = NetworkConfigType.None; + _networkLogs = new NetworkLayerLogs(); _logger.LogInformation("CellularNetworkContext 重置完成"); } catch (Exception ex) diff --git a/CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj b/CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj index 45f6941..7a73d4c 100644 --- a/CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj +++ b/CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj @@ -15,11 +15,13 @@ + + diff --git a/CoreAgent.Infrastructure/Services/CustomWSClient/CustomWebSocketClient.cs b/CoreAgent.Infrastructure/Services/CustomWSClient/CustomWebSocketClient.cs new file mode 100644 index 0000000..53ba575 --- /dev/null +++ b/CoreAgent.Infrastructure/Services/CustomWSClient/CustomWebSocketClient.cs @@ -0,0 +1,172 @@ +using CoreAgent.Domain.Helpers; +using CoreAgent.Domain.Interfaces.CustomWSClient; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebSocket4Net; + +namespace CoreAgent.Infrastructure.Services.CustomWSClient +{ + public class CustomWebSocketClient : IDisposable + { + private readonly ILogger logger; + private readonly string serverUrl; + private WebSocket? webSocket; + protected readonly ICustomMessageHandler messageHandler; + private bool _disposed; + + protected CustomWebSocketClient(ILogger logger, string serverUrl, ICustomMessageHandler messageHandler) + { + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + this.serverUrl = $"ws://{serverUrl}"; + this.messageHandler = messageHandler ?? throw new ArgumentNullException(nameof(messageHandler)); + } + + public void Start() + { + try + { + logger.LogInformation("正在启动WebSocket客户端,连接到服务器: {ServerUrl}", serverUrl); + webSocket = new WebSocket4Net.WebSocket(serverUrl); + ConfigureWebSocketHandlers(); + webSocket.EnableAutoSendPing = false; + webSocket.Open(); + logger.LogInformation("WebSocket客户端启动成功"); + } + catch (Exception ex) + { + logger.LogError(ex, "WebSocket客户端启动失败: {Message}", ex.Message); + throw; + } + } + + private void ConfigureWebSocketHandlers() + { + try + { + webSocket!.Opened += (s, e) => HandleOpen(e); + webSocket.Closed += (s, e) => HandleClosed(e); + webSocket.Error += (s, e) => HandleError(e); + webSocket.MessageReceived += (s, e) => HandleMessage(e); + webSocket.DataReceived += (s, e) => HandleDataReceivedMessage(e); + logger.LogDebug("WebSocket事件处理器配置完成"); + } + catch (Exception ex) + { + logger.LogError(ex, "配置WebSocket事件处理器时发生错误: {Message}", ex.Message); + throw; + } + } + + private void HandleOpen(EventArgs @event) + { + try + { + logger.LogInformation("WebSocket已连接到服务器: {ServerUrl}", serverUrl); + } + catch (Exception ex) + { + logger.LogError(ex, "处理WebSocket打开事件时发生错误: {Message}", ex.Message); + } + } + + private void HandleClosed(EventArgs @event) + { + try + { + logger.LogInformation("WebSocket连接已关闭,状态: {State}", webSocket?.State); + } + catch (Exception ex) + { + logger.LogError(ex, "处理WebSocket关闭事件时发生错误: {Message}", ex.Message); + } + } + + private void HandleError(SuperSocket.ClientEngine.ErrorEventArgs ex) + { + try + { + logger.LogError(ex.Exception, "WebSocket发生错误: {Message}", ex.Exception.Message); + } + catch (Exception e) + { + logger.LogError(e, "处理WebSocket错误事件时发生异常: {Message}", e.Message); + } + } + + private void HandleMessage(MessageReceivedEventArgs e) + { + try + { + if (webSocket is { State: WebSocketState.Connecting or WebSocketState.Open }) + { + logger.LogDebug("收到WebSocket消息: {Message}", e.Message); + messageHandler.HandleMessage(e.Message, new ObserverCustomWebSocketClient(webSocket, logger)); + } + else + { + logger.LogWarning("收到消息时WebSocket状态异常: {State}, 消息内容: {Message}", webSocket!.State, e.Message); + } + } + catch (Exception ex) + { + logger.LogError(ex, "处理WebSocket消息时发生错误: {Message}, 原始消息: {OriginalMessage}", ex.Message, e.Message); + } + } + + private void HandleDataReceivedMessage(DataReceivedEventArgs data) + { + try + { + string message = Encoding.UTF8.GetString(data.Data); + logger.LogDebug("收到WebSocket二进制数据: {Message}", message); + } + catch (Exception ex) + { + logger.LogError(ex, "处理WebSocket二进制数据时发生错误: {Message}, 数据: {Data}", ex.Message, data.ObjToJson()); + } + } + + public void Stop() + { + try + { + logger.LogInformation("正在停止WebSocket客户端"); + webSocket?.Close(); + webSocket?.Dispose(); + logger.LogInformation("WebSocket客户端已停止"); + } + catch (Exception ex) + { + logger.LogError(ex, "停止WebSocket客户端时发生错误: {Message}", ex.Message); + throw; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + Stop(); + } + _disposed = true; + } + } + + ~CustomWebSocketClient() + { + Dispose(false); + } + } +} diff --git a/CoreAgent.Infrastructure/Services/CustomWSClient/ObserverCustomWebSocketClient.cs b/CoreAgent.Infrastructure/Services/CustomWSClient/ObserverCustomWebSocketClient.cs new file mode 100644 index 0000000..9ec62b3 --- /dev/null +++ b/CoreAgent.Infrastructure/Services/CustomWSClient/ObserverCustomWebSocketClient.cs @@ -0,0 +1,143 @@ +using CoreAgent.Domain.Interfaces.CustomWSClient; +using Microsoft.Extensions.Logging; +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.Tasks; +using WebSocket4Net; +using WebSocket = WebSocket4Net.WebSocket; +using WebSocketState = WebSocket4Net.WebSocketState; + +namespace CoreAgent.Infrastructure.Services.CustomWSClient +{ + public class ObserverCustomWebSocketClient : IObserverCustomWebSocketClient, IDisposable + { + private readonly WebSocket _client; + private readonly ILogger _logger; + private readonly BlockingCollection _sendQueue; + private readonly CancellationTokenSource _cancellationTokenSource; + private readonly Task _sendTask; + private bool _disposed; + private const int SEND_INTERVAL_MS = 100; // 发送间隔,可以根据需要调整 + + public ObserverCustomWebSocketClient(WebSocket client, ILogger logger) + { + _client = client ?? throw new ArgumentNullException(nameof(client)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + + _sendQueue = new BlockingCollection(); + _cancellationTokenSource = new CancellationTokenSource(); + _sendTask = Task.Run(ProcessSendQueue); + + _logger.LogInformation("WebSocket消息发送队列已启动"); + } + + public void SendMessage(string message) + { + if (string.IsNullOrEmpty(message)) + { + _logger.LogWarning("尝试发送空消息"); + return; + } + + try + { + _logger.LogDebug("将消息加入发送队列: {Message}", message); + _sendQueue.Add(message); + } + catch (Exception ex) + { + _logger.LogError(ex, "将消息加入发送队列时发生错误: {Message}", message); + throw; + } + } + + private async Task ProcessSendQueue() + { + try + { + _logger.LogInformation("开始处理WebSocket消息发送队列"); + foreach (var message in _sendQueue.GetConsumingEnumerable(_cancellationTokenSource.Token)) + { + try + { + await SendMessageInternalAsync(message); + await Task.Delay(SEND_INTERVAL_MS); // 添加发送间隔 + } + catch (Exception ex) + { + _logger.LogError(ex, "发送WebSocket消息时发生错误: {Message}", message); + } + } + } + catch (OperationCanceledException) + { + _logger.LogInformation("WebSocket消息发送队列处理已取消"); + } + catch (Exception ex) + { + _logger.LogError(ex, "WebSocket消息发送队列处理过程中发生错误"); + } + } + + private async Task SendMessageInternalAsync(string message) + { + if (_client.State != WebSocketState.Open) + { + _logger.LogWarning("WebSocket未处于打开状态,无法发送消息。当前状态: {State}, 消息内容: {Message}", + _client.State, message); + return; + } + + try + { + _logger.LogDebug("正在发送WebSocket消息: {Message}", message); + await Task.Run(() => _client.Send(message)); + _logger.LogDebug("WebSocket消息发送成功"); + } + catch (Exception ex) + { + _logger.LogError(ex, "发送WebSocket消息时发生错误: {Message}", message); + throw; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + _cancellationTokenSource.Cancel(); + _sendQueue.CompleteAdding(); + try + { + _sendTask.Wait(TimeSpan.FromSeconds(5)); + } + catch (AggregateException ex) + { + _logger.LogError(ex, "等待消息发送队列处理完成时发生错误"); + } + _sendQueue.Dispose(); + _cancellationTokenSource.Dispose(); + } + _disposed = true; + } + } + + ~ObserverCustomWebSocketClient() + { + Dispose(false); + } + } +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/IMSLogMessageHandler.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/IMSLogMessageHandler.cs new file mode 100644 index 0000000..cca4daa --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/IMSLogMessageHandler.cs @@ -0,0 +1,264 @@ +using CoreAgent.Domain.Interfaces.CustomWSClient; +using CoreAgent.Domain.Interfaces.Network; +using CoreAgent.Domain.Models.Protocol; +using CoreAgent.Infrastructure.Contexts; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + /// + /// IMS协议消息处理器 + /// 负责处理IMS相关的WebSocket消息,包括用户更新、短信、邀请等功能 + /// + public class IMSLogMessageHandler : ICustomMessageHandler, IDisposable + { + private readonly ILogger _logger; + private int _messageId = 0; + private string _currentMessageId = string.Empty; + private readonly Action _messageCallback; + private readonly ICellularNetworkContext _context; + private readonly BlockingCollection<(string MessageData, IObserverCustomWebSocketClient Observer)> _messageQueue; + private readonly CancellationTokenSource _cancellationTokenSource; + private readonly Task _processTask; + private bool _disposed; + + public IMSLogMessageHandler(ILogger logger, ICellularNetworkContext context, Action action) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _messageCallback = action ?? throw new ArgumentNullException(nameof(action)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + + _messageQueue = new BlockingCollection<(string, IObserverCustomWebSocketClient)>(); + _cancellationTokenSource = new CancellationTokenSource(); + _processTask = Task.Run(ProcessMessageQueue); + + _logger.LogInformation("IMS协议消息处理器初始化完成,消息队列已启动"); + } + + public void HandleMessage(string messageData, IObserverCustomWebSocketClient observer) + { + try + { + _logger.LogDebug("将消息加入处理队列: {MessageData}", messageData); + _messageQueue.Add((messageData, observer)); + } + catch (Exception ex) + { + _logger.LogError(ex, "将消息加入队列时发生错误: {MessageData}", messageData); + } + } + + private async Task ProcessMessageQueue() + { + try + { + _logger.LogInformation("开始处理IMS消息队列"); + foreach (var (messageData, observer) in _messageQueue.GetConsumingEnumerable(_cancellationTokenSource.Token)) + { + try + { + await ProcessMessageAsync(messageData, observer); + } + catch (Exception ex) + { + _logger.LogError(ex, "处理队列中的消息时发生错误: {MessageData}", messageData); + } + } + } + catch (OperationCanceledException) + { + _logger.LogInformation("IMS消息队列处理已取消"); + } + catch (Exception ex) + { + _logger.LogError(ex, "IMS消息队列处理过程中发生错误"); + } + } + + private async Task ProcessMessageAsync(string messageData, IObserverCustomWebSocketClient observer) + { + try + { + _logger.LogDebug("开始处理IMS协议消息: {MessageData}", messageData); + var data = JObject.Parse(messageData); + string messageType = data["message"]!.ToString(); + _logger.LogInformation("收到IMS协议消息类型: {MessageType}", messageData); + await HandleMessageByTypeAsync(messageType, data, observer); + } + catch (Exception ex) + { + _logger.LogError(ex, "处理IMS协议消息时发生错误: {MessageData}", messageData); + } + } + + private async Task HandleMessageByTypeAsync(string messageType, JObject data, IObserverCustomWebSocketClient observer) + { + _currentMessageId = _messageId.ToString(); + + switch (messageType) + { + case "ready": + await HandleReadyMessageAsync(observer); + break; + case "config_get": + await HandleConfigGetMessageAsync(data, observer); + break; + case "config_set": + await HandleConfigSetMessageAsync(observer); + break; + case "log_get": + await HandleLogGetMessageAsync(data, observer); + break; + case "stats": + await HandleStatsMessageAsync(observer); + break; + default: + _logger.LogWarning("收到未知的IMS协议消息类型: {MessageType}", messageType); + await Task.Run(() => observer.SendMessage(LayerLogslevelSetting(false))); + break; + } + } + + private async Task HandleReadyMessageAsync(IObserverCustomWebSocketClient observer) + { + string readyResponse = CreateMessage("config_get"); + _logger.LogInformation("发送ready响应: {Response}", readyResponse); + await Task.Run(() => observer.SendMessage(readyResponse)); + } + + private async Task HandleConfigGetMessageAsync(JObject data, IObserverCustomWebSocketClient observer) + { + if (_currentMessageId == data["message_id"]!.ToString()) + { + _logger.LogInformation("处理config_get请求"); + var responseArray = new JArray + { + CreateRegisterMessage("users_update"), + CreateRegisterMessage("sms"), + CreateRegisterMessage("invite"), + CreateStatsMessage(), + SettingBaseLayerLogslevel(JObject.Parse(data["logs"].ToString())) + }; + _logger.LogInformation("发送config_get响应: {Response}", responseArray.ToString()); + await Task.Run(() => observer.SendMessage(responseArray.ToString())); + } + else + { + _logger.LogWarning("config_get消息ID不匹配: 收到={ReceivedId}, 期望={ExpectedId}", + data["message_id"]!.ToString(), _currentMessageId); + } + } + + private async Task HandleConfigSetMessageAsync(IObserverCustomWebSocketClient observer) + { + _messageId++; + string configResponse = LayerLogslevelSetting(true); + _logger.LogInformation("发送config_set响应: {Response}", configResponse); + await Task.Run(() => observer.SendMessage(configResponse)); + //_currentMessageId = _messageId.ToString(); + } + + private async Task HandleLogGetMessageAsync(JObject data, IObserverCustomWebSocketClient observer) + { + if (JArray.FromObject(data["logs"]).Count > 0) + { + _messageId++; + string logResponse = LayerLogslevelSetting(false); + _logger.LogInformation("发送log_get响应: {Response}", logResponse); + await Task.Run(() => observer.SendMessage(logResponse)); + _currentMessageId = _messageId.ToString(); + await Task.Run(() => _messageCallback.Invoke(data.ToString())); + } + } + + private async Task HandleStatsMessageAsync(IObserverCustomWebSocketClient observer) + { + _messageId++; + string statsResponse = CreateStatsMessage(); + _logger.LogInformation("发送stats响应: {Response}", statsResponse); + await Task.Run(() => observer.SendMessage(statsResponse)); + } + + private string CreateMessage(string message) + { + _messageId++; + return JObject.FromObject(new { message, message_id = _messageId }).ToString(); + } + + private JObject CreateRegisterMessage(string register) + { + _messageId++; + return JObject.FromObject(new { message = "register", message_id = _messageId, register }); + } + + private string CreateStatsMessage() + { + _messageId++; + return CreateMessage("stats"); + } + + private JObject SettingBaseLayerLogslevel(JObject keyValues, bool isCloseSystemInfo = false) + { + _messageId++; + keyValues.Remove("rotate"); + keyValues.Remove("path"); + keyValues.Remove("count"); + keyValues["bcch"] = isCloseSystemInfo; + + return JObject.FromObject(new + { + message = "config_set", + logs = keyValues, + message_id = _messageId + }); + } + + private string LayerLogslevelSetting(bool isHead = false) + { + _messageId++; + BaseNetworkLog logtype = new BaseNetworkLog + { + Timeout = isHead ? 0 : 1, + MinLogCount = 64, + MaxLogCount = 2048, + LayerConfig = _context.NetworkLogs.ImsLog, + Message = "log_get", + IncludeHeaders = isHead, + MessageId = _messageId + }; + return JObject.FromObject(logtype).ToString(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + _cancellationTokenSource.Cancel(); + _messageQueue.CompleteAdding(); + _processTask.Wait(); + _cancellationTokenSource.Dispose(); + _messageQueue.Dispose(); + } + _disposed = true; + } + } + + ~IMSLogMessageHandler() + { + Dispose(false); + } + } +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolLogsProviderObserver.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolLogsProviderObserver.cs new file mode 100644 index 0000000..dabb207 --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolLogsProviderObserver.cs @@ -0,0 +1,147 @@ +using CoreAgent.Domain.Interfaces.Network; +using CoreAgent.Domain.Interfaces.ProtocolLogHandlers; +using CoreAgent.Domain.Models.Network; +using CoreAgent.Infrastructure.Contexts; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + /// + /// 协议日志提供者观察者 + /// 负责接收、缓存和转发协议日志数据 + /// 使用生产者-消费者模式处理日志数据流 + /// + public class ProtocolLogsProviderObserver : IProtocolLogsProviderObserver + { + /// + /// 用于存储待处理的协议日志消息的阻塞队列 + /// + private readonly static BlockingCollection BlockingQueue = new BlockingCollection(); + + /// + /// 日志记录器 + /// + private readonly ILogger logger; + + /// + /// 网络上下文,用于检查网络状态 + /// + private readonly CellularNetworkContext networkContext; + + + /// + /// 初始化协议日志提供者观察者 + /// + /// 网络上下文 + /// 日志记录器 + public ProtocolLogsProviderObserver(CellularNetworkContext networkContext, ILogger logger) + { + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + this.networkContext = networkContext ?? throw new ArgumentNullException(nameof(networkContext)); + + logger.LogInformation("ProtocolLogsProviderObserver 初始化完成"); + _ = Task.Run(Consumer); + logger.LogInformation("消费者任务已启动"); + } + + /// + /// 接收并处理新的协议日志数据 + /// + /// 协议日志消息 + public void OnData(string msg) + { + if (string.IsNullOrEmpty(msg)) + { + logger.LogWarning("收到空的协议日志消息"); + return; + } + + try + { + logger.LogDebug("收到新的协议日志消息: {Message}", msg); + Producer(msg); + } + catch (Exception ex) + { + logger.LogError(ex, "处理协议日志消息时发生错误: {Message}", msg); + } + } + + /// + /// 生产者方法:将消息添加到阻塞队列中 + /// + /// 要添加的消息 + private void Producer(string message) + { + try + { + var networkState = networkContext.GetNetworkState(); + if (networkState.CurrentStatus == NetworkStatus.Connected) + { + logger.LogDebug("网络已连接,将消息添加到队列: {Message}", message); + BlockingQueue.Add(message); + } + else + { + logger.LogWarning("网络未连接,丢弃消息: {Message}", message); + } + } + catch (Exception ex) + { + logger.LogError(ex, "添加消息到队列时发生错误: {Message}", message); + throw; + } + } + + /// + /// 消费者方法:从队列中获取并处理消息 + /// + public async Task Consumer() + { + logger.LogInformation("消费者任务开始运行"); + + try + { + while (networkContext.GetNetworkState().CurrentStatus == NetworkStatus.Connected) + { + try + { + if (BlockingQueue.TryTake(out var message, TimeSpan.FromMilliseconds(1000))) + { + logger.LogDebug("从队列中获取到消息: {Message}", message); + // TODO: 实现消息发送逻辑 + // await client.SendAsync(message, true); + } + else + { + await Task.Delay(1000); + } + } + catch (Exception ex) + { + logger.LogError(ex, "处理队列消息时发生错误"); + await Task.Delay(1000); // 发生错误时等待一段时间再继续 + } + } + } + catch (OperationCanceledException) + { + logger.LogWarning("消费者任务被取消"); + } + catch (Exception ex) + { + logger.LogError(ex, "消费者任务发生未处理的错误"); + } + finally + { + logger.LogInformation("消费者任务已结束"); + } + } + } +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSHandleLogs.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSHandleLogs.cs new file mode 100644 index 0000000..c0f987c --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSHandleLogs.cs @@ -0,0 +1,30 @@ +using CoreAgent.Domain.Interfaces.CustomWSClient; +using CoreAgent.Domain.Interfaces.ProtocolLogHandlers; +using CoreAgent.Infrastructure.Services.CustomWSClient; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + public class ProtocolMSHandleLogs : CustomWebSocketClient, IProtocollHandleLogs + { + protected ProtocolMSHandleLogs(ILogger logger, string serverUrl, ICustomMessageHandler messageHandler) : base(logger, serverUrl, messageHandler) + { + + } + + public void RunStart() + { + + } + + public void RunStop() + { + + } + } +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSParesHandleLogs.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSParesHandleLogs.cs new file mode 100644 index 0000000..7630c1f --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSParesHandleLogs.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + internal class ProtocolMSParesHandleLogs + { + } +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolParesHandleLogs.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolParesHandleLogs.cs new file mode 100644 index 0000000..bdfcd0b --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolParesHandleLogs.cs @@ -0,0 +1,41 @@ +using CoreAgent.Domain.Models.Protocol; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + public abstract class ProtocolParesHandleLogs + { + #region Regex + public readonly Regex _regExpPhy = new Regex(@"^([a-f0-9\-]+)\s+([a-f0-9\-]+)\s+([\d\.\-]+) (\w+): (.+)"); + public readonly Regex _regExpInfo1 = new Regex(@"^([\w\-]+): (.+)"); + public readonly Regex _regExpInfo2 = new Regex(@"^([\w]+) (.+)"); + public readonly Regex _regExpParams1 = new Regex(@"\s+"); + public readonly Regex _regExpParams2 = new Regex(@"=|:"); + public readonly Regex _regExpIP = new Regex(@"^(len=\d+)\s+(\S+)\s+(.*)"); + public readonly Regex _regExpIPsec = new Regex(@"^len=(\d+)\s+(.*)"); + public readonly Regex _regExpIKEV2 = new Regex(@"^(\S+)\s+(.*)"); + public readonly Regex _regExpSDULen = new Regex(@"SDU_len=(\d+)"); + public readonly Regex _regExpSIP = new Regex(@"^([:\.\[\]\da-f]+)\s+(\S+) (.+)"); + public readonly Regex _regExpMediaReq = new Regex(@"^(\S+) (.+)"); + public readonly Regex _regExpSignalRecord = new Regex(@"Link:\s([\w\d]+)@(\d+)"); + public readonly Regex _regExpCellID = new Regex(@"^([a-f0-9\-]+) (.+)"); + public readonly Regex _regExpRRC_UE_ID = new Regex(@"Changing UE_ID to 0x(\d+)"); + public readonly Regex _regExpRRC_TMSI = new Regex(@"(5G|m)-TMSI '([\dA-F]+)'H"); + public readonly Regex _regExpRRC_NEW_ID = new Regex(@"newUE-Identity (['\dA-FH]+)"); + public readonly Regex _regExpRRC_CRNTI = new Regex(@"c-RNTI '([\dA-F]+)'H"); + public readonly Regex _regExpNAS_TMSI = new Regex(@"m-TMSI = 0x([\da-f]+)"); + public readonly Regex _regExpNAS_5GTMSI = new Regex(@"5G-TMSI = 0x([\da-f]+)"); + public readonly Regex _regExpRRC_BC = new Regex(@"(EUTRA|MRDC|NR|NRDC) band combinations"); + public readonly Regex _regExpPDCCH = new Regex(@"^\s*(.+)=(\d+)$"); + public readonly Regex _regExpS1NGAP = new Regex(@"^([\da-f\-]+)\s+([\da-f\-]+) (([^\s]+) .+)"); + public readonly Regex _regExpECPRI = new Regex(@"len=(\d+)"); + public readonly Regex _regExpHexDump = new Regex(@"^[\da-f]+:(\s+[\da-f]{2}){1,16}\s+.{1,16}$"); + #endregion + public abstract Task GetTryParesLogDataHandle(ProtocolLog model); + } +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanHandleLogs.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanHandleLogs.cs new file mode 100644 index 0000000..e842f8a --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanHandleLogs.cs @@ -0,0 +1,30 @@ +using CoreAgent.Domain.Interfaces.CustomWSClient; +using CoreAgent.Domain.Interfaces.ProtocolLogHandlers; +using CoreAgent.Infrastructure.Services.CustomWSClient; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + public class ProtocolRanHandleLogs : CustomWebSocketClient, IProtocollHandleLogs + { + protected ProtocolRanHandleLogs(ILogger logger, string serverUrl, ICustomMessageHandler messageHandler) : base(logger, serverUrl, messageHandler) + { + + } + + public void RunStart() + { + + } + + public void RunStop() + { + + } + } +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanParesHandleLogs.cs.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanParesHandleLogs.cs.cs new file mode 100644 index 0000000..df4dc78 --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanParesHandleLogs.cs.cs @@ -0,0 +1,284 @@ +using CoreAgent.Domain.Helpers; +using CoreAgent.Domain.Interfaces.ProtocolLogHandlers; +using CoreAgent.Domain.Models.Protocol; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + + + + public class ProtocolLogsParesRanHandle : ProtocolParesHandleLogs + { + private readonly ILogger logger; + private readonly IProtocolLogsProviderObserver observer; + public ProtocolLogsParesRanHandle(IProtocolLogsProviderObserver observer, ILogger logger) + { + this.observer = observer; + this.logger = logger; + } + + public override async Task GetTryParesLogDataHandle(ProtocolLog model) + { + try + { + if (model is { Logs: null }) + { + logger.LogError($"logs is null =====>GetTryParesLogDataHandle Data {model?.ObjToJson()}"); + return; + } + var ParseJsonData = model.Logs.ToString().JsonToObj(); + //var parseResultData = RanLogParseHandle(ParseJsonData, (model.MessageId ?? 0)); + //if (parseResultData.Any()) + //{ + // var MsgData = new { data = parseResultData, MessageType = CSCIMessageType.ProtocolLogsRAN }.ObjToJson(); + // logger.LogInformation($"OnData:{MsgData}"); + // observer.OnData(MsgData); + //} + } + catch (Exception ex) + { + logger.LogError($"GetTryParesLogDataHandle Data {model?.ObjToJson()}"); + logger.LogError(ex.ToString()); + } + } + + + //#region 分析 + //private List RanLogParseHandle(ProtocolLogDetail[] data, int MessageID) + //{ + // List cellulars = new List(); + // try + // { + // foreach (var msg in data) + // { + // ProtocolLogslayerType LayerType; + // Enum.TryParse(msg.layer, out LayerType); + // string info = string.Empty; + // string TMIS = string.Empty; + // string MessageInfo = msg.data[0]; + // if (LayerType == ProtocolLogslayerType.RRC) + // { + // var reg = _regExpRRC_UE_ID.Match(MessageInfo); + // if (reg is { Success: true }) + // { + // int ue_id = Convert.ToInt32(reg.Groups[1].ToString(), 16); + + // } + // reg = _regExpInfo1.Match(MessageInfo); + // if (reg.Success) + // { + // info = reg.Groups[1].Value; + // MessageInfo = reg.Groups[2].Value; + // GetlogListRRC(msg, MessageInfo); + + // } + // reg = _regExpRRC_BC.Match(MessageInfo); + // if (reg is { Success: true }) + // { + // string result = string.Join("\n", msg.data); + + // } + // } + // else if (LayerType == ProtocolLogslayerType.NAS) + // { + // var reg = _regExpInfo1.Match(MessageInfo); + // if (reg is { Success: true }) + // { + // info = reg.Groups[1].Value; + // MessageInfo = reg.Groups[2].Value; + // TMIS = GetlogListNAS(msg, MessageInfo); + // if (info.Equals("BCCH_NR")) + // { + + // } + + // } + // } + // else if (LayerType == ProtocolLogslayerType.PHY) + // { + // var reg = _regExpPhy.Match(MessageInfo); + // if (reg is { Success: true }) + // { + // int cell = Convert.ToInt32(reg.Groups[1].Value, 16); + // int rnti = Convert.ToInt32(reg.Groups[2].Value, 16); + // var channel = reg.Groups[4].Value; + // string[] frames = reg.Groups[3].Value.Split('.'); + // int frame = Convert.ToInt32(frames[0]) - 0; + // int slot = Convert.ToInt32(frames[1]) - 0; + // } + + // } + // else if (LayerType == ProtocolLogslayerType.MAC) + // { + // var reg = _regExpCellID.Match(MessageInfo); + // if (reg is { Success: true }) + // { + // int cell = Convert.ToInt32(reg.Groups[1].Value, 16); + // MessageInfo = reg.Groups[2].Value; + // } + // } + // CellularNetworkProtocolLogsEntity entity = new CellularNetworkProtocolLogsEntity + // { + // MessageID = MessageID, + // CellID = msg.cell, + // Timestamp = msg.timestamp, + // UEID = msg.ue_id, + // Time = msg.timestamp.UnixTimeStamp13ToBeijingTime().TimeOfDay, + // ProtocolLayer = LayerType, + // Info = info, + // TMSI = TMIS, + // Message = MessageInfo, + // ProtocolType = msg.src, + // Index = msg.idx, + // Direction = msg.dir switch + // { + // "UL" => DirectionLogsType.UL, + // "DL" => DirectionLogsType.DL, + // _ => DirectionLogsType._ + // }, + // MessageData = msg.data.ToArray(), + // }; + // cellulars.Add(entity); + // } + // return cellulars; + // } + // catch (Exception ex) + // { + // logger.Error("ran logs analysis combination" + ex.Message); + // return cellulars; + // } + //} + + //private void GetlogListRRC(ProtocolNetWorkCoreLogsDetailEntity log, string logType) + //{ + // try + // { + // switch (logType.ToLower()) + // { + // case "sib1": + // break; + // case "sib": + // break; + // case "rrc connection request": + // var lte = GetFindData(log.data, _regExpRRC_TMSI); + // if (lte is { Success: true }) + // { + // int tmsi = GetTMSI(log, lte.Groups[2].Value.ToString()); + // } + // break; + // case "rrc connection reconfiguration": + // var connection = GetFindData(log.data, _regExpRRC_TMSI); + // if (connection is { Success: true }) + // { + // int rnti = GetRNTI(log, connection.Groups[1].Value); + // } + // break; + // case "rrc connection reestablishment request": + // var request = GetFindData(log.data, _regExpRRC_TMSI); + // if (request is { Success: true }) + // { + // int rnti = GetRNTI(log, request.Groups[1].Value); + // } + // break; + // case "rrc setup request": + // var RRCrequest = GetFindData(log.data, _regExpRRC_TMSI); + // break; + // case "ue capability information": + + // break; + // default: + // break; + // } + // } + // catch (Exception ex) + // { + // logger.Error("GetlogListRRC" + ex.Message); + // } + //} + + //private string GetlogListNAS(ProtocolNetWorkCoreLogsDetailEntity log, string logType) + //{ + // switch (logType.ToLower()) + // { + // case "attach accept": + // var lte = GetFindData(log.data, _regExpNAS_TMSI); + // if (lte is not null && !string.IsNullOrWhiteSpace(lte.Groups[1]?.ToString())) + // { + + // int tmsi = GetTMSI(log, lte.Groups[1].Value); + // return lte.Groups[1].Value; + + // } + // break; + // case "attach request": + // var data = log.data; + // break; + // case "registration accept": + // var Nr = GetFindData(log.data, _regExpNAS_5GTMSI); + // if (Nr is not null && !string.IsNullOrWhiteSpace(Nr?.Groups[1]?.ToString())) + // { + // int tmsi = GetTMSI(log, Nr.Groups[1].Value); + // return Nr.Groups[1].Value; + // } + // break; + // case "registration request": + // var requestData = log.data; + // break; + + // } + // return string.Empty; + + //} + + //private Match GetFindData(List data, Regex regExp) + //{ + // if (data.Any()) + // { + // for (var i = 0; i < data.Count; i++) + // { + // Match m = regExp.Match(data[i]); + // if (m.Success) + // return m; + // } + // } + // return default; + //} + + //private int GetTMSI(ProtocolNetWorkCoreLogsDetailEntity log, string tmsi) + //{ + // return Convert.ToInt32(tmsi, 16); + //} + + //private int GetRNTI(ProtocolNetWorkCoreLogsDetailEntity log, string rnti) + //{ + // // 定义正则表达式模式 + // string pattern = @"'([\dA-F]+)'H"; + + // // 创建正则表达式对象 + // Regex regex = new Regex(pattern); + + // // 进行匹配 + // Match match = regex.Match(rnti); + + // // 检查是否有匹配 + // if (match.Success) + // return Convert.ToInt32(match.Groups[1].Value, 16); + // else return 0; + //} + + //private bool GetCheckLayerTypeInfo(string layer) + //{ + // string[] ArraryLayer = new string[] { "PDSCH", "PDCCH", "EPDCCH", "PUSCH", "PUCCH", "NPDSCH", "NPUSCH", "NPBCH", "BCCH-NR", "HINTS", "SRS", "CSI", "SIM-Even", "IP-SIM" }; + // return ArraryLayer.Any(s => s.Equals(layer)); + //} + //#endregion + } + +} diff --git a/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/RanLogMessageHandler.cs b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/RanLogMessageHandler.cs new file mode 100644 index 0000000..76720eb --- /dev/null +++ b/CoreAgent.Infrastructure/Services/ProtocolLogHandlers/RanLogMessageHandler.cs @@ -0,0 +1,368 @@ +using CoreAgent.Domain.Interfaces.CustomWSClient; +using CoreAgent.Domain.Interfaces.Network; +using CoreAgent.Domain.Models.Protocol; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CoreAgent.Infrastructure.Services.ProtocolLogHandlers +{ + /// + /// RAN协议WebSocket消息处理器 + /// 负责处理无线接入网(RAN)相关的WebSocket消息,包括配置获取、日志获取等功能 + /// + public class RanLogMessageHandler : ICustomMessageHandler, IDisposable + { + private readonly ILogger _logger; + private int _messageId = 0; + private string _currentMessageId = string.Empty; + private readonly Action _messageCallback; + private readonly ICellularNetworkContext _networkContext; + private readonly BlockingCollection<(string MessageData, IObserverCustomWebSocketClient Observer)> _messageQueue; + private readonly CancellationTokenSource _cancellationTokenSource; + private readonly Task _processTask; + private bool _disposed; + + /// + /// 初始化RAN协议消息处理器 + /// + /// 日志记录器 + /// 蜂窝网络上下文 + /// 消息回调处理函数 + public RanLogMessageHandler(ILogger logger, ICellularNetworkContext context, Action action) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _messageCallback = action ?? throw new ArgumentNullException(nameof(action)); + _networkContext = context ?? throw new ArgumentNullException(nameof(context)); + + _messageQueue = new BlockingCollection<(string, IObserverCustomWebSocketClient)>(); + _cancellationTokenSource = new CancellationTokenSource(); + _processTask = Task.Run(ProcessMessageQueue); + + _logger.LogInformation("RAN协议消息处理器初始化完成,消息队列已启动"); + } + + /// + /// 处理接收到的WebSocket消息 + /// 将消息加入处理队列,由队列处理器异步处理 + /// + /// 接收到的消息数据 + /// WebSocket客户端观察者 + public void HandleMessage(string messageData, IObserverCustomWebSocketClient observer) + { + try + { + _logger.LogDebug("将消息加入处理队列: {MessageData}", messageData); + _messageQueue.Add((messageData, observer)); + } + catch (Exception ex) + { + _logger.LogError(ex, "将消息加入队列时发生错误: {MessageData}", messageData); + } + } + + /// + /// 处理消息队列中的消息 + /// 持续从队列中获取消息并处理,直到队列关闭或取消 + /// + private async Task ProcessMessageQueue() + { + try + { + _logger.LogInformation("开始处理消息队列"); + foreach (var (messageData, observer) in _messageQueue.GetConsumingEnumerable(_cancellationTokenSource.Token)) + { + try + { + await ProcessMessageAsync(messageData, observer); + } + catch (Exception ex) + { + _logger.LogError(ex, "处理队列中的消息时发生错误: {MessageData}", messageData); + } + } + } + catch (OperationCanceledException) + { + _logger.LogInformation("消息队列处理已取消"); + } + catch (Exception ex) + { + _logger.LogError(ex, "消息队列处理过程中发生错误"); + } + } + + /// + /// 处理单条消息 + /// 解析消息类型并分发到对应的处理方法 + /// + /// 消息数据 + /// WebSocket客户端观察者 + private async Task ProcessMessageAsync(string messageData, IObserverCustomWebSocketClient observer) + { + try + { + _logger.LogDebug("开始处理RAN协议消息: {MessageData}", messageData); + var jsonData = JObject.Parse(messageData); + string messageType = jsonData["message"]!.ToString(); + _logger.LogInformation("收到RAN协议消息类型: {MessageType}", messageType); + await ProcessMessageByTypeAsync(messageType, jsonData, observer); + } + catch (Exception ex) + { + _logger.LogError(ex, "处理RAN协议消息时发生错误: {MessageData}", messageData); + } + } + + /// + /// 根据消息类型分发到对应的处理方法 + /// + /// 消息类型 + /// 消息数据 + /// WebSocket客户端观察者 + private async Task ProcessMessageByTypeAsync(string messageType, JObject data, IObserverCustomWebSocketClient observer) + { + _logger.LogDebug("开始处理RAN协议消息类型: {MessageType}", messageType); + switch (messageType) + { + case "ready": + await HandleReadyMessageAsync(observer); + break; + case "config_get": + await HandleConfigGetMessageAsync(data, observer); + break; + case "config_set": + await HandleConfigSetMessageAsync(observer); + break; + case "log_get": + await HandleLogGetMessageAsync(data, observer); + break; + case "stats": + await HandleStatsMessageAsync(observer); + break; + default: + _logger.LogWarning("收到未知的RAN协议消息类型: {MessageType}", messageType); + break; + } + } + + /// + /// 处理ready消息 + /// 发送config_get请求,准备获取配置信息 + /// + /// WebSocket客户端观察者 + private async Task HandleReadyMessageAsync(IObserverCustomWebSocketClient observer) + { + _messageId++; + string readyResponse = JObject.FromObject(new { message = "config_get", message_id = _messageId }).ToString(); + _logger.LogInformation("发送ready响应: {Response}", readyResponse); + await Task.Run(() => observer.SendMessage(readyResponse)); + _currentMessageId = _messageId.ToString(); + } + + /// + /// 处理config_get消息 + /// 发送统计信息和基础层日志配置 + /// + /// 消息数据 + /// WebSocket客户端观察者 + private async Task HandleConfigGetMessageAsync(JObject data, IObserverCustomWebSocketClient observer) + { + if (_currentMessageId == data["message_id"]!.ToString()) + { + _logger.LogInformation("处理config_get请求"); + var responseArray = new JArray(); + + _messageId++; + var statsConfig = new { message = "stats", message_id = _messageId, rf = false, samples = false }; + responseArray.Add(JObject.FromObject(statsConfig)); + + _messageId++; + string baseLayerConfig = ConfigureBaseLayerLogs(data); + responseArray.Add(JObject.Parse(baseLayerConfig)); + + _logger.LogInformation("发送config_get响应: {Response}", responseArray.ToString()); + await Task.Run(() => observer.SendMessage(responseArray.ToString())); + } + else + { + _logger.LogWarning("config_get消息ID不匹配: 收到={ReceivedId}, 期望={ExpectedId}", + data["message_id"]!.ToString(), _currentMessageId); + } + } + + /// + /// 处理config_set消息 + /// 发送层日志配置 + /// + /// WebSocket客户端观察者 + private async Task HandleConfigSetMessageAsync(IObserverCustomWebSocketClient observer) + { + _messageId++; + string configResponse = ConfigureLayerLogs(true); + await Task.Run(() => observer.SendMessage(configResponse)); + _currentMessageId = _messageId.ToString(); + _logger.LogInformation("发送config_set响应: {Response}", configResponse); + } + + /// + /// 处理log_get消息 + /// 发送日志配置并触发回调 + /// + /// 消息数据 + /// WebSocket客户端观察者 + private async Task HandleLogGetMessageAsync(JObject data, IObserverCustomWebSocketClient observer) + { + if (_currentMessageId == data["message_id"]!.ToString()) + { + _messageId++; + string logResponse = ConfigureLayerLogs(false); + await Task.Run(() => observer.SendMessage(logResponse)); + _currentMessageId = _messageId.ToString(); + _logger.LogInformation("发送log_get响应: {Response}", logResponse); + } + else + { + _logger.LogWarning("log_get消息ID不匹配: 收到={ReceivedId}, 期望={ExpectedId}", + data["message_id"]!.ToString(), _currentMessageId); + } + await Task.Run(() => _messageCallback.Invoke(data.ToString())); + } + + /// + /// 处理stats消息 + /// 发送统计信息请求 + /// + /// WebSocket客户端观察者 + private async Task HandleStatsMessageAsync(IObserverCustomWebSocketClient observer) + { + _messageId++; + string statsResponse = JObject.FromObject(new + { + message = "stats", + message_id = _messageId, + rf = false, + samples = false + }).ToString(); + await Task.Run(() => observer.SendMessage(statsResponse)); + _logger.LogInformation("发送stats响应: {Response}", statsResponse); + } + + /// + /// 配置基础层日志 + /// 设置各种日志级别的开关状态 + /// + /// 配置键值对 + /// 是否关闭系统信息 + /// 配置后的JSON字符串 + private string ConfigureBaseLayerLogs(JObject keyValues, bool isCloseSystemInfo = false) + { + _logger.LogDebug("开始配置基础层日志: {KeyValues}", keyValues.ToString()); + + // 移除不需要的配置项 + if (keyValues.Remove("rotate") && keyValues.Remove("path") && keyValues.Remove("count")) + { + _logger.LogDebug("已移除rotate、path和count配置项"); + } + + // 设置系统信息相关配置 + keyValues["bcch"] = isCloseSystemInfo; + keyValues["cch"] = isCloseSystemInfo; + keyValues["cell_meas"] = isCloseSystemInfo; + keyValues["csi"] = isCloseSystemInfo; + + // 设置其他配置项 + keyValues["dci_size"] = false; + keyValues["mib"] = false; + keyValues["rep"] = false; + keyValues["signal"] = false; + + var configMessage = new + { + message = "config_set", + logs = keyValues, + message_id = _messageId, + }; + + string response = JObject.FromObject(configMessage).ToString(); + _logger.LogInformation("基础层日志配置完成: {Response}", response); + return response; + } + + /// + /// 配置层日志 + /// 设置日志超时、计数等参数 + /// + /// 是否包含头部信息 + /// 配置后的JSON字符串 + private string ConfigureLayerLogs(bool includeHeaders = false) + { + _logger.LogDebug("开始配置层日志: IncludeHeaders={IncludeHeaders}", includeHeaders); + + var logConfig = new BaseNetworkLog + { + Timeout = includeHeaders ? 0 : 1, + MinLogCount = 64, + MaxLogCount = 2048, + LayerConfig = _networkContext.NetworkLogs.RanLog, + Message = "log_get", + IncludeHeaders = includeHeaders, + MessageId = _messageId, + }; + + string response = JObject.FromObject(logConfig).ToString(); + _logger.LogInformation("层日志配置完成: {Response}", response); + return response; + } + + /// + /// 释放资源 + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// 释放资源的具体实现 + /// + /// 是否正在释放托管资源 + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + _cancellationTokenSource.Cancel(); + _messageQueue.CompleteAdding(); + try + { + _processTask.Wait(TimeSpan.FromSeconds(5)); + } + catch (AggregateException ex) + { + _logger.LogError(ex, "等待消息队列处理完成时发生错误"); + } + _messageQueue.Dispose(); + _cancellationTokenSource.Dispose(); + } + _disposed = true; + } + } + + /// + /// 析构函数 + /// + ~RanLogMessageHandler() + { + Dispose(false); + } + } +}