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);
+ }
+ }
+}