Compare commits

...

4 Commits

  1. 1
      CoreAgent.API/publish.bat
  2. 6
      CoreAgent.Domain/CoreAgent.Domain.csproj
  3. 4
      CoreAgent.Domain/Entities/NetworkConfiguration.cs
  4. 48
      CoreAgent.Domain/Helpers/JsonHelper.cs
  5. 13
      CoreAgent.Domain/Interfaces/CustomWSClient/ICustomMessageHandler.cs
  6. 13
      CoreAgent.Domain/Interfaces/CustomWSClient/IObserverCustomWebSocketClient.cs
  7. 6
      CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs
  8. 13
      CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocolLogsProviderObserver.cs
  9. 15
      CoreAgent.Domain/Interfaces/ProtocolLogHandlers/IProtocollHandleLogs.cs
  10. 55
      CoreAgent.Domain/Models/Protocol/BaseNetworkLog.cs
  11. 34
      CoreAgent.Domain/Models/Protocol/DirectionLogsType.cs
  12. 80
      CoreAgent.Domain/Models/Protocol/ImsLayerLog.cs
  13. 27
      CoreAgent.Domain/Models/Protocol/LogLevel.cs
  14. 200
      CoreAgent.Domain/Models/Protocol/MobileUserIdentity.cs
  15. 54
      CoreAgent.Domain/Models/Protocol/NetworkLayerLogs.cs
  16. 242
      CoreAgent.Domain/Models/Protocol/ProtocolLayerType.cs
  17. 258
      CoreAgent.Domain/Models/Protocol/ProtocolLayerTypeExtensions.cs
  18. 97
      CoreAgent.Domain/Models/Protocol/ProtocolLog.cs
  19. 76
      CoreAgent.Domain/Models/Protocol/ProtocolLogDetail.cs
  20. 338
      CoreAgent.Domain/Models/Protocol/ProtocolLogParsedResult.cs
  21. 136
      CoreAgent.Domain/Models/Protocol/RanLayerLog.cs
  22. 219
      CoreAgent.Domain/Models/Protocol/UserNetworkIdentity.cs
  23. 9
      CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs
  24. 2
      CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj
  25. 172
      CoreAgent.Infrastructure/Services/CustomWSClient/CustomWebSocketClient.cs
  26. 143
      CoreAgent.Infrastructure/Services/CustomWSClient/ObserverCustomWebSocketClient.cs
  27. 12
      CoreAgent.Infrastructure/Services/Network/NetworkInterfaceManager.cs
  28. 256
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/IMSLogMessageHandler.cs
  29. 147
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolLogsProviderObserver.cs
  30. 30
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSHandleLogs.cs
  31. 12
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolMSParesHandleLogs.cs
  32. 41
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolParesHandleLogs.cs
  33. 30
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanHandleLogs.cs
  34. 83
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanParesHandleLogs.cs
  35. 362
      CoreAgent.Infrastructure/Services/ProtocolLogHandlers/RanLogMessageHandler.cs

1
CoreAgent.API/publish.bat

@ -0,0 +1 @@
dotnet publish -r linux-x64 -c Debug -p:PublishSingeFile=true --self-contained -o D:\HistoryCode\CoreAgent\src\output

6
CoreAgent.Domain/CoreAgent.Domain.csproj

@ -6,6 +6,12 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Entities\NetworkLogs\**" />
<EmbeddedResource Remove="Entities\NetworkLogs\**" />
<None Remove="Entities\NetworkLogs\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />

4
CoreAgent.Domain/Entities/NetworkConfiguration.cs

@ -120,9 +120,9 @@ namespace CoreAgent.Domain.Entities
// 验证频段格式
foreach (var band in Band)
{
if (!band.StartsWith("B") || !int.TryParse(band.Substring(1), out _))
if ((!band.StartsWith("B") && !band.StartsWith("N")) || !int.TryParse(band.Substring(1), out _))
{
yield return new ValidationResult($"频段格式不正确: {band},应为 B1、B2 等格式");
yield return new ValidationResult($"频段格式不正确: {band},应为 B1、B2 或者 N78 等格式");
}
}
}

48
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
{
/// <summary>
/// 对象序列化
/// </summary>
/// <param name="obj">对象</param>
/// <param name="isUseTextJson">是否使用textjson</param>
/// <returns>返回json字符串</returns>
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);
}
}
/// <summary>
/// json反序列化obj
/// </summary>
/// <typeparam name="T">反序列类型</typeparam>
/// <param name="strJson">json</param>
/// <param name="isUseTextJson">是否使用textjson</param>
/// <returns>返回对象</returns>
public static T JsonToObj<T>(this string strJson, bool isUseTextJson = false)
{
if (isUseTextJson)
{
return System.Text.Json.JsonSerializer.Deserialize<T>(strJson);
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(strJson);
}
}
}
}

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

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

6
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
/// </summary>
NetworkConfigType CurrentConfigType { get; }
/// <summary>
/// 网络层日志配置
/// </summary>
NetworkLayerLogs NetworkLogs { get; }
#endregion
#region 生命周期管理

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

15
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();
}
}

55
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;
/// <summary>
/// 基础网络日志实体类
/// 提供网络日志的通用属性和配置
/// </summary>
/// <typeparam name="T">日志层类型(如ImsLayerLog或RanLayerLog)</typeparam>
public class BaseNetworkLog<T>
{
/// <summary>
/// 超时时间(毫秒)
/// </summary>
[JsonProperty("timeout")]
public int Timeout { get; set; }
/// <summary>
/// 最小日志数量
/// </summary>
[JsonProperty("min")]
public int MinLogCount { get; set; }
/// <summary>
/// 最大日志数量
/// </summary>
[JsonProperty("max")]
public int MaxLogCount { get; set; }
/// <summary>
/// 日志层配置
/// </summary>
[JsonProperty("layers")]
public T LayerConfig { get; set; }
/// <summary>
/// 日志消息
/// </summary>
[JsonProperty("message")]
public string Message { get; set; }
/// <summary>
/// 是否包含消息头
/// </summary>
[JsonProperty("headers")]
public bool IncludeHeaders { get; set; }
/// <summary>
/// 消息ID
/// </summary>
[JsonProperty("message_id")]
public int MessageId { get; set; }
}

34
CoreAgent.Domain/Models/Protocol/DirectionLogsType.cs

@ -0,0 +1,34 @@
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 日志方向类型枚举
/// 定义了协议日志的传输方向
/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分
/// </summary>
public enum DirectionLogsType
{
/// <summary>
/// 未知方向
/// </summary>
Unknown = 0,
/// <summary>
/// 上行方向(UE到网络)
/// </summary>
Uplink = 1,
/// <summary>
/// 下行方向(网络到UE)
/// </summary>
Downlink = 2,
/// <summary>
/// 双向
/// </summary>
Bidirectional = 3,
/// <summary>
/// 内部处理
/// </summary>
Internal = 4
}

80
CoreAgent.Domain/Models/Protocol/ImsLayerLog.cs

@ -0,0 +1,80 @@
using System;
using System.Text.Json.Serialization;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// IMS层日志实体类
/// 该实体用于记录IMS(IP多媒体子系统)相关的各层日志信息
/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分
/// </summary>
public class ImsLayerLog
{
/// <summary>
/// CX协议层日志级别
/// </summary>
public string CX { get; set; }
/// <summary>
/// IMS协议层日志级别
/// </summary>
public string IMS { get; set; }
/// <summary>
/// IPSEC协议层日志级别
/// </summary>
public string IPSEC { get; set; }
/// <summary>
/// MEDIA协议层日志级别
/// </summary>
public string MEDIA { get; set; }
/// <summary>
/// MMS协议层日志级别
/// </summary>
public string MMS { get; set; }
/// <summary>
/// RX协议层日志级别
/// </summary>
public string RX { get; set; }
/// <summary>
/// SIP协议层日志级别
/// </summary>
public string SIP { get; set; }
/// <summary>
/// 初始化IMS层日志级别
/// </summary>
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();
}
/// <summary>
/// 更新指定层的日志级别
/// </summary>
/// <param name="layerName">层名称</param>
/// <param name="logLevel">日志级别</param>
/// <returns>是否更新成功</returns>
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;
}
}

27
CoreAgent.Domain/Models/Protocol/LogLevel.cs

@ -0,0 +1,27 @@
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 日志级别枚举
/// </summary>
public enum LogLevel
{
/// <summary>
/// 调试级别
/// </summary>
Debug,
/// <summary>
/// 信息级别
/// </summary>
Info,
/// <summary>
/// 警告级别
/// </summary>
Warn,
/// <summary>
/// 错误级别
/// </summary>
Error
}

200
CoreAgent.Domain/Models/Protocol/MobileUserIdentity.cs

@ -0,0 +1,200 @@
using Newtonsoft.Json;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 移动用户身份信息
/// 用于存储移动网络用户的基本身份和位置信息
/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分
/// </summary>
public class MobileUserIdentity
{
/// <summary>
/// 公共陆地移动网络标识
/// Public Land Mobile Network Identifier
/// </summary>
[JsonProperty("plmn")]
public string? Plmn { get; set; }
/// <summary>
/// 旧的临时移动用户标识
/// Old Temporary Mobile Subscriber Identity
/// </summary>
[JsonProperty("oldTmsi")]
public string? OldTmsi { get; set; }
/// <summary>
/// 临时移动用户标识
/// Temporary Mobile Subscriber Identity
/// </summary>
[JsonProperty("tmsi")]
public string? Tmsi { get; set; }
/// <summary>
/// 国际移动用户标识
/// International Mobile Subscriber Identity
/// </summary>
[JsonProperty("imsi")]
public string? Imsi { get; set; }
/// <summary>
/// 小区ID
/// Cell Identifier
/// </summary>
[JsonProperty("cellId")]
public int? CellId { get; set; }
/// <summary>
/// 用户设备ID
/// User Equipment Identifier
/// </summary>
[JsonProperty("ueId")]
public int? UeId { get; set; }
/// <summary>
/// 初始化移动用户身份信息的新实例
/// </summary>
public MobileUserIdentity()
{
}
/// <summary>
/// 初始化移动用户身份信息的新实例
/// </summary>
/// <param name="plmn">公共陆地移动网络标识</param>
/// <param name="oldTmsi">旧的临时移动用户标识</param>
/// <param name="tmsi">临时移动用户标识</param>
/// <param name="imsi">国际移动用户标识</param>
/// <param name="cellId">小区ID</param>
/// <param name="ueId">用户设备ID</param>
public MobileUserIdentity(
string? plmn = null,
string? oldTmsi = null,
string? tmsi = null,
string? imsi = null,
int? cellId = null,
int? ueId = null)
{
Plmn = plmn;
OldTmsi = oldTmsi;
Tmsi = tmsi;
Imsi = imsi;
CellId = cellId;
UeId = ueId;
}
/// <summary>
/// 检查是否包含有效的用户身份信息
/// </summary>
/// <returns>是否包含有效信息</returns>
public bool HasValidIdentity()
{
return !string.IsNullOrWhiteSpace(Imsi) ||
!string.IsNullOrWhiteSpace(Tmsi) ||
UeId.HasValue;
}
/// <summary>
/// 检查是否包含位置信息
/// </summary>
/// <returns>是否包含位置信息</returns>
public bool HasLocationInfo()
{
return !string.IsNullOrWhiteSpace(Plmn) || CellId.HasValue;
}
/// <summary>
/// 获取用户身份摘要信息
/// </summary>
/// <returns>摘要信息</returns>
public string GetIdentitySummary()
{
var parts = new List<string>();
if (!string.IsNullOrWhiteSpace(Imsi))
parts.Add($"IMSI:{Imsi}");
if (!string.IsNullOrWhiteSpace(Tmsi))
parts.Add($"TMSI:{Tmsi}");
if (UeId.HasValue)
parts.Add($"UE:{UeId}");
if (!string.IsNullOrWhiteSpace(Plmn))
parts.Add($"PLMN:{Plmn}");
if (CellId.HasValue)
parts.Add($"Cell:{CellId}");
return parts.Count > 0 ? string.Join(" | ", parts) : "No Identity Info";
}
/// <summary>
/// 检查TMSI是否发生变化
/// </summary>
/// <returns>TMSI是否发生变化</returns>
public bool HasTmsiChanged()
{
return !string.IsNullOrWhiteSpace(OldTmsi) &&
!string.IsNullOrWhiteSpace(Tmsi) &&
!OldTmsi.Equals(Tmsi, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// 创建身份信息的副本
/// </summary>
/// <returns>新的移动用户身份信息</returns>
public MobileUserIdentity Copy()
{
return new MobileUserIdentity
{
Plmn = Plmn,
OldTmsi = OldTmsi,
Tmsi = Tmsi,
Imsi = Imsi,
CellId = CellId,
UeId = UeId
};
}
/// <summary>
/// 更新TMSI信息
/// </summary>
/// <param name="newTmsi">新的TMSI</param>
public void UpdateTmsi(string? newTmsi)
{
if (!string.IsNullOrWhiteSpace(Tmsi))
{
OldTmsi = Tmsi;
}
Tmsi = newTmsi;
}
/// <summary>
/// 转换为JSON字符串
/// </summary>
/// <returns>JSON字符串</returns>
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
/// <summary>
/// 从JSON字符串创建移动用户身份信息
/// </summary>
/// <param name="json">JSON字符串</param>
/// <returns>移动用户身份信息</returns>
public static MobileUserIdentity FromJson(string json)
{
return JsonConvert.DeserializeObject<MobileUserIdentity>(json) ?? new MobileUserIdentity();
}
/// <summary>
/// 重写ToString方法
/// </summary>
/// <returns>字符串表示</returns>
public override string ToString()
{
return GetIdentitySummary();
}
}

54
CoreAgent.Domain/Models/Protocol/NetworkLayerLogs.cs

@ -0,0 +1,54 @@
using System;
using System.Text.Json.Serialization;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 网络层日志集合
/// 用于统一管理不同网络层的日志配置
/// </summary>
public class NetworkLayerLogs
{
/// <summary>
/// IMS层日志配置
/// </summary>
public ImsLayerLog ImsLog { get; set; }
/// <summary>
/// RAN层日志配置
/// </summary>
public RanLayerLog RanLog { get; set; }
/// <summary>
/// 初始化所有网络层的日志级别
/// </summary>
/// <param name="isNonStandaloneMode">是否为非独立组网模式(NSA模式)</param>
public void InitializeAllLogLevels(bool isNonStandaloneMode = false)
{
ImsLog = new ImsLayerLog();
RanLog = new RanLayerLog();
ImsLog.InitializeLogLevels();
RanLog.InitializeLogLevels(isNonStandaloneMode);
}
/// <summary>
/// 更新指定网络层和指定层的日志级别
/// </summary>
/// <param name="networkType">网络类型("IMS" 或 "RAN")</param>
/// <param name="layerName">层名称</param>
/// <param name="logLevel">日志级别</param>
/// <returns>是否更新成功</returns>
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
};
}
}

242
CoreAgent.Domain/Models/Protocol/ProtocolLayerType.cs

@ -0,0 +1,242 @@
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 协议层类型枚举
/// 定义了系统中支持的各种协议层类型
/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分
/// </summary>
public enum ProtocolLayerType
{
/// <summary>
/// 无协议层类型
/// </summary>
NONE = 0,
/// <summary>
/// GTP-U协议层
/// GPRS Tunnelling Protocol User Plane
/// </summary>
GTPU = 1,
/// <summary>
/// LPPa协议层
/// LTE Positioning Protocol Annex
/// </summary>
LPPa = 2,
/// <summary>
/// M2AP协议层
/// M2 Application Protocol
/// </summary>
M2AP = 3,
/// <summary>
/// MAC协议层
/// Medium Access Control
/// </summary>
MAC = 4,
/// <summary>
/// NAS协议层
/// Non-Access Stratum
/// </summary>
NAS = 5,
/// <summary>
/// NGAP协议层
/// Next Generation Application Protocol
/// </summary>
NGAP = 6,
/// <summary>
/// NRPPa协议层
/// NR Positioning Protocol Annex
/// </summary>
NRPPa = 7,
/// <summary>
/// PDCP协议层
/// Packet Data Convergence Protocol
/// </summary>
PDCP = 8,
/// <summary>
/// PROD协议层
/// Production Protocol
/// </summary>
PROD = 9,
/// <summary>
/// PHY协议层
/// Physical Layer
/// </summary>
PHY = 10,
/// <summary>
/// RLC协议层
/// Radio Link Control
/// </summary>
RLC = 11,
/// <summary>
/// RRC协议层
/// Radio Resource Control
/// </summary>
RRC = 12,
/// <summary>
/// S1AP协议层
/// S1 Application Protocol
/// </summary>
S1AP = 13,
/// <summary>
/// TRX协议层
/// Transceiver Protocol
/// </summary>
TRX = 14,
/// <summary>
/// X2AP协议层
/// X2 Application Protocol
/// </summary>
X2AP = 15,
/// <summary>
/// XnAP协议层
/// Xn Application Protocol
/// </summary>
XnAP = 16,
/// <summary>
/// IP协议层
/// Internet Protocol
/// </summary>
IP = 17,
/// <summary>
/// IMS协议层
/// IP Multimedia Subsystem
/// </summary>
IMS = 18,
/// <summary>
/// CX协议层
/// Diameter CX Interface
/// </summary>
CX = 19,
/// <summary>
/// RX协议层
/// Diameter RX Interface
/// </summary>
RX = 20,
/// <summary>
/// S6协议层
/// Diameter S6 Interface
/// </summary>
S6 = 21,
/// <summary>
/// S13协议层
/// Diameter S13 Interface
/// </summary>
S13 = 22,
/// <summary>
/// SGsAP协议层
/// SGs Application Protocol
/// </summary>
SGsAP = 23,
/// <summary>
/// SBcAP协议层
/// SBc Application Protocol
/// </summary>
SBcAP = 24,
/// <summary>
/// LCSAP协议层
/// LCS Application Protocol
/// </summary>
LCSAP = 25,
/// <summary>
/// N12协议层
/// Diameter N12 Interface
/// </summary>
N12 = 26,
/// <summary>
/// N8协议层
/// Diameter N8 Interface
/// </summary>
N8 = 27,
/// <summary>
/// N17协议层
/// Diameter N17 Interface
/// </summary>
N17 = 28,
/// <summary>
/// N50协议层
/// Diameter N50 Interface
/// </summary>
N50 = 29,
/// <summary>
/// N13协议层
/// Diameter N13 Interface
/// </summary>
N13 = 30,
/// <summary>
/// NL1协议层
/// Network Layer 1
/// </summary>
NL1 = 31,
/// <summary>
/// HTTP2协议层
/// Hypertext Transfer Protocol 2
/// </summary>
HTTP2 = 32,
/// <summary>
/// EPDG协议层
/// Evolved Packet Data Gateway
/// </summary>
EPDG = 33,
/// <summary>
/// IKEV2协议层
/// Internet Key Exchange Version 2
/// </summary>
IKEV2 = 34,
/// <summary>
/// IPSEC协议层
/// Internet Protocol Security
/// </summary>
IPSEC = 35,
/// <summary>
/// MEDIA协议层
/// Media Protocol
/// </summary>
MEDIA = 36,
/// <summary>
/// MMS协议层
/// Multimedia Messaging Service
/// </summary>
MMS = 37,
/// <summary>
/// SIP协议层
/// Session Initiation Protocol
/// </summary>
SIP = 38
}

258
CoreAgent.Domain/Models/Protocol/ProtocolLayerTypeExtensions.cs

@ -0,0 +1,258 @@
using System.ComponentModel;
using System.Reflection;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// ProtocolLayerType 枚举扩展方法
/// 提供协议层类型的实用功能
/// </summary>
public static class ProtocolLayerTypeExtensions
{
/// <summary>
/// 获取协议层类型的描述信息
/// </summary>
/// <param name="protocolLayerType">协议层类型</param>
/// <returns>描述信息</returns>
public static string GetDescription(this ProtocolLayerType protocolLayerType)
{
var field = protocolLayerType.GetType().GetField(protocolLayerType.ToString());
var attribute = field?.GetCustomAttribute<DescriptionAttribute>();
return attribute?.Description ?? protocolLayerType.ToString();
}
/// <summary>
/// 获取协议层类型的显示名称
/// </summary>
/// <param name="protocolLayerType">协议层类型</param>
/// <returns>显示名称</returns>
public static string GetDisplayName(this ProtocolLayerType protocolLayerType)
{
return protocolLayerType switch
{
ProtocolLayerType.NONE => "无",
ProtocolLayerType.GTPU => "GTP-U",
ProtocolLayerType.LPPa => "LPPa",
ProtocolLayerType.M2AP => "M2AP",
ProtocolLayerType.MAC => "MAC",
ProtocolLayerType.NAS => "NAS",
ProtocolLayerType.NGAP => "NGAP",
ProtocolLayerType.NRPPa => "NRPPa",
ProtocolLayerType.PDCP => "PDCP",
ProtocolLayerType.PROD => "PROD",
ProtocolLayerType.PHY => "PHY",
ProtocolLayerType.RLC => "RLC",
ProtocolLayerType.RRC => "RRC",
ProtocolLayerType.S1AP => "S1AP",
ProtocolLayerType.TRX => "TRX",
ProtocolLayerType.X2AP => "X2AP",
ProtocolLayerType.XnAP => "XnAP",
ProtocolLayerType.IP => "IP",
ProtocolLayerType.IMS => "IMS",
ProtocolLayerType.CX => "CX",
ProtocolLayerType.RX => "RX",
ProtocolLayerType.S6 => "S6",
ProtocolLayerType.S13 => "S13",
ProtocolLayerType.SGsAP => "SGsAP",
ProtocolLayerType.SBcAP => "SBcAP",
ProtocolLayerType.LCSAP => "LCSAP",
ProtocolLayerType.N12 => "N12",
ProtocolLayerType.N8 => "N8",
ProtocolLayerType.N17 => "N17",
ProtocolLayerType.N50 => "N50",
ProtocolLayerType.N13 => "N13",
ProtocolLayerType.NL1 => "NL1",
ProtocolLayerType.HTTP2 => "HTTP/2",
ProtocolLayerType.EPDG => "EPDG",
ProtocolLayerType.IKEV2 => "IKEv2",
ProtocolLayerType.IPSEC => "IPSec",
ProtocolLayerType.MEDIA => "MEDIA",
ProtocolLayerType.MMS => "MMS",
ProtocolLayerType.SIP => "SIP",
_ => protocolLayerType.ToString()
};
}
/// <summary>
/// 判断是否为RAN相关协议层
/// </summary>
/// <param name="protocolLayerType">协议层类型</param>
/// <returns>是否为RAN协议层</returns>
public static bool IsRanProtocol(this ProtocolLayerType protocolLayerType)
{
return protocolLayerType switch
{
ProtocolLayerType.GTPU or
ProtocolLayerType.LPPa or
ProtocolLayerType.M2AP or
ProtocolLayerType.MAC or
ProtocolLayerType.NAS or
ProtocolLayerType.NGAP or
ProtocolLayerType.NRPPa or
ProtocolLayerType.PDCP or
ProtocolLayerType.PHY or
ProtocolLayerType.RLC or
ProtocolLayerType.RRC or
ProtocolLayerType.S1AP or
ProtocolLayerType.TRX or
ProtocolLayerType.X2AP or
ProtocolLayerType.XnAP => true,
_ => false
};
}
/// <summary>
/// 判断是否为IMS相关协议层
/// </summary>
/// <param name="protocolLayerType">协议层类型</param>
/// <returns>是否为IMS协议层</returns>
public static bool IsImsProtocol(this ProtocolLayerType protocolLayerType)
{
return protocolLayerType switch
{
ProtocolLayerType.IMS or
ProtocolLayerType.CX or
ProtocolLayerType.RX or
ProtocolLayerType.S6 or
ProtocolLayerType.S13 or
ProtocolLayerType.SGsAP or
ProtocolLayerType.SBcAP or
ProtocolLayerType.LCSAP or
ProtocolLayerType.N12 or
ProtocolLayerType.N8 or
ProtocolLayerType.N17 or
ProtocolLayerType.N50 or
ProtocolLayerType.N13 or
ProtocolLayerType.HTTP2 or
ProtocolLayerType.EPDG or
ProtocolLayerType.IKEV2 or
ProtocolLayerType.IPSEC or
ProtocolLayerType.MEDIA or
ProtocolLayerType.MMS or
ProtocolLayerType.SIP => true,
_ => false
};
}
/// <summary>
/// 判断是否为Diameter协议层
/// </summary>
/// <param name="protocolLayerType">协议层类型</param>
/// <returns>是否为Diameter协议层</returns>
public static bool IsDiameterProtocol(this ProtocolLayerType protocolLayerType)
{
return protocolLayerType switch
{
ProtocolLayerType.CX or
ProtocolLayerType.RX or
ProtocolLayerType.S6 or
ProtocolLayerType.S13 or
ProtocolLayerType.N12 or
ProtocolLayerType.N8 or
ProtocolLayerType.N17 or
ProtocolLayerType.N50 or
ProtocolLayerType.N13 => true,
_ => false
};
}
/// <summary>
/// 获取协议层类型的分类
/// </summary>
/// <param name="protocolLayerType">协议层类型</param>
/// <returns>协议层分类</returns>
public static string GetCategory(this ProtocolLayerType protocolLayerType)
{
return protocolLayerType switch
{
ProtocolLayerType.NONE => "None",
ProtocolLayerType.GTPU or
ProtocolLayerType.LPPa or
ProtocolLayerType.M2AP or
ProtocolLayerType.MAC or
ProtocolLayerType.NAS or
ProtocolLayerType.NGAP or
ProtocolLayerType.NRPPa or
ProtocolLayerType.PDCP or
ProtocolLayerType.PHY or
ProtocolLayerType.RLC or
ProtocolLayerType.RRC or
ProtocolLayerType.S1AP or
ProtocolLayerType.TRX or
ProtocolLayerType.X2AP or
ProtocolLayerType.XnAP => "RAN",
ProtocolLayerType.IMS or
ProtocolLayerType.CX or
ProtocolLayerType.RX or
ProtocolLayerType.S6 or
ProtocolLayerType.S13 or
ProtocolLayerType.SGsAP or
ProtocolLayerType.SBcAP or
ProtocolLayerType.LCSAP or
ProtocolLayerType.N12 or
ProtocolLayerType.N8 or
ProtocolLayerType.N17 or
ProtocolLayerType.N50 or
ProtocolLayerType.N13 or
ProtocolLayerType.HTTP2 or
ProtocolLayerType.EPDG or
ProtocolLayerType.IKEV2 or
ProtocolLayerType.IPSEC or
ProtocolLayerType.MEDIA or
ProtocolLayerType.MMS or
ProtocolLayerType.SIP => "IMS",
ProtocolLayerType.IP => "Network",
ProtocolLayerType.NL1 => "Network",
ProtocolLayerType.PROD => "Production",
_ => "Other"
};
}
/// <summary>
/// 从字符串转换为ProtocolLayerType枚举
/// </summary>
/// <param name="value">字符串值</param>
/// <returns>ProtocolLayerType枚举值,如果转换失败返回NONE</returns>
public static ProtocolLayerType FromString(string value)
{
if (string.IsNullOrWhiteSpace(value))
return ProtocolLayerType.NONE;
return Enum.TryParse<ProtocolLayerType>(value, true, out var result)
? result
: ProtocolLayerType.NONE;
}
/// <summary>
/// 获取所有RAN协议层类型
/// </summary>
/// <returns>RAN协议层类型数组</returns>
public static ProtocolLayerType[] GetRanProtocols()
{
return Enum.GetValues<ProtocolLayerType>()
.Where(p => p.IsRanProtocol())
.ToArray();
}
/// <summary>
/// 获取所有IMS协议层类型
/// </summary>
/// <returns>IMS协议层类型数组</returns>
public static ProtocolLayerType[] GetImsProtocols()
{
return Enum.GetValues<ProtocolLayerType>()
.Where(p => p.IsImsProtocol())
.ToArray();
}
/// <summary>
/// 获取所有Diameter协议层类型
/// </summary>
/// <returns>Diameter协议层类型数组</returns>
public static ProtocolLayerType[] GetDiameterProtocols()
{
return Enum.GetValues<ProtocolLayerType>()
.Where(p => p.IsDiameterProtocol())
.ToArray();
}
}

97
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;
/// <summary>
/// 协议日志实体类
/// </summary>
public record class ProtocolLog
{
/// <summary>
/// 消息ID
/// </summary>
[JsonProperty("message_id")]
public int? MessageId { get; set; }
/// <summary>
/// 消息头信息
/// </summary>
[JsonProperty("headers")]
public string[]? Headers { get; set; }
/// <summary>
/// 消息内容
/// </summary>
[JsonProperty("message")]
public string Message { get; set; }
/// <summary>
/// 消息类型
/// </summary>
[JsonProperty("type")]
public string? Type { get; set; }
/// <summary>
/// 消息名称
/// </summary>
[JsonProperty("name")]
public string? Name { get; set; }
/// <summary>
/// 协议版本
/// </summary>
[JsonProperty("version")]
public string? Version { get; set; }
/// <summary>
/// 时间戳
/// </summary>
[JsonProperty("time")]
public double? Time { get; set; }
/// <summary>
/// UTC时间戳
/// </summary>
[JsonProperty("utc")]
public double? Utc { get; set; }
/// <summary>
/// 日志明细
/// </summary>
[JsonProperty("logs")]
public JToken? Logs { get; set; }
/// <summary>
/// 初始化协议日志实体类的新实例
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="type">消息类型</param>
/// <param name="version">协议版本</param>
/// <param name="time">时间戳</param>
/// <param name="utc">UTC时间戳</param>
/// <param name="logs">日志明细</param>
/// <param name="messageId">消息ID</param>
/// <param name="headers">消息头信息</param>
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;
}
}

76
CoreAgent.Domain/Models/Protocol/ProtocolLogDetail.cs

@ -0,0 +1,76 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 协议日志明细
/// </summary>
public class ProtocolLogDetail
{
/// <summary>
/// 源信息
/// </summary>
[JsonProperty("src")]
public string Src { get; set; }
/// <summary>
/// 索引
/// </summary>
[JsonProperty("idx")]
public int Idx { get; set; }
/// <summary>
/// 日志级别
/// </summary>
[JsonProperty("level")]
public int Level { get; set; }
/// <summary>
/// 方向
/// </summary>
[JsonProperty("dir")]
public string Dir { get; set; }
/// <summary>
/// 时间戳
/// </summary>
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
/// <summary>
/// 小区信息
/// </summary>
[JsonProperty("cell")]
public int? Cell { get; set; }
/// <summary>
/// 数据列表
/// </summary>
[JsonProperty("data")]
public List<string> Data { get; set; }
/// <summary>
/// 层信息
/// </summary>
[JsonProperty("layer")]
public string Layer { get; set; }
/// <summary>
/// UE标识
/// </summary>
[JsonProperty("ue_id")]
public int? UeId { get; set; }
/// <summary>
/// 帧信息
/// </summary>
[JsonProperty("frame")]
public int? Frame { get; set; }
/// <summary>
/// 时隙信息
/// </summary>
[JsonProperty("slot")]
public int? Slot { get; set; }
}

338
CoreAgent.Domain/Models/Protocol/ProtocolLogParsedResult.cs

@ -0,0 +1,338 @@
using Newtonsoft.Json;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 协议日志解析结果
/// 用于存储ProtocolLog解析后的分析结果,用于数据传输和处理
/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分
/// </summary>
public class ProtocolLogParsedResult
{
/// <summary>
/// 唯一标识符
/// </summary>
[JsonProperty("id")]
public string Id { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// 日志索引
/// </summary>
[JsonProperty("index")]
public int? Index { get; set; }
/// <summary>
/// 消息ID
/// </summary>
[JsonProperty("messageId")]
public int? MessageId { get; set; }
/// <summary>
/// 协议层类型
/// </summary>
[JsonProperty("protocolLayer")]
public ProtocolLayerType ProtocolLayer { get; set; }
/// <summary>
/// 协议类型描述
/// </summary>
[JsonProperty("protocolType")]
public string ProtocolType { get; set; } = string.Empty;
/// <summary>
/// 用户设备ID
/// </summary>
[JsonProperty("ueId")]
public int? UeId { get; set; }
/// <summary>
/// 公共陆地移动网络标识
/// </summary>
[JsonProperty("plmn")]
public string? Plmn { get; set; }
/// <summary>
/// 临时移动用户标识
/// </summary>
[JsonProperty("tmsi")]
public string? Tmsi { get; set; }
/// <summary>
/// 国际移动设备标识
/// </summary>
[JsonProperty("imei")]
public string? Imei { get; set; }
/// <summary>
/// 国际移动用户标识
/// </summary>
[JsonProperty("imsi")]
public string? Imsi { get; set; }
/// <summary>
/// 小区ID
/// </summary>
[JsonProperty("cellId")]
public int? CellId { get; set; }
/// <summary>
/// 小区信息
/// </summary>
[JsonProperty("cell")]
public string? Cell { get; set; }
/// <summary>
/// 日志信息
/// </summary>
[JsonProperty("info")]
public string? Info { get; set; }
/// <summary>
/// 消息内容
/// </summary>
[JsonProperty("message")]
public string? Message { get; set; }
/// <summary>
/// 消息数据数组
/// </summary>
[JsonProperty("messageData")]
public string[]? MessageData { get; set; }
/// <summary>
/// 时间间隔
/// </summary>
[JsonProperty("time")]
public TimeSpan Time { get; set; }
/// <summary>
/// 时间戳
/// </summary>
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
/// <summary>
/// 日志方向
/// </summary>
[JsonProperty("direction")]
public DirectionLogsType Direction { get; set; }
/// <summary>
/// 协议层分类
/// </summary>
[JsonProperty("category")]
public string Category => ProtocolLayer.GetCategory();
/// <summary>
/// 协议层显示名称
/// </summary>
[JsonProperty("displayName")]
public string DisplayName => ProtocolLayer.GetDisplayName();
/// <summary>
/// 初始化协议日志解析结果的新实例
/// </summary>
public ProtocolLogParsedResult()
{
}
/// <summary>
/// 初始化协议日志解析结果的新实例
/// </summary>
/// <param name="messageId">消息ID</param>
/// <param name="index">日志索引</param>
/// <param name="protocolLayer">协议层类型</param>
/// <param name="ueId">用户设备ID</param>
/// <param name="plmn">公共陆地移动网络标识</param>
/// <param name="tmsi">临时移动用户标识</param>
/// <param name="imei">国际移动设备标识</param>
/// <param name="imsi">国际移动用户标识</param>
/// <param name="cellId">小区ID</param>
/// <param name="cell">小区信息</param>
/// <param name="info">日志信息</param>
/// <param name="message">消息内容</param>
/// <param name="messageData">消息数据数组</param>
/// <param name="direction">日志方向</param>
public ProtocolLogParsedResult(
int? messageId = null,
int? index = null,
ProtocolLayerType protocolLayer = ProtocolLayerType.NONE,
int? ueId = null,
string? plmn = null,
string? tmsi = null,
string? imei = null,
string? imsi = null,
int? cellId = null,
string? cell = null,
string? info = null,
string? message = null,
string[]? messageData = null,
DirectionLogsType direction = DirectionLogsType.Unknown)
{
MessageId = messageId;
Index = index;
ProtocolLayer = protocolLayer;
UeId = ueId;
Plmn = plmn;
Tmsi = tmsi;
Imei = imei;
Imsi = imsi;
CellId = cellId;
Cell = cell;
Info = info;
Message = message;
MessageData = messageData;
Direction = direction;
ProtocolType = protocolLayer.GetDisplayName();
}
/// <summary>
/// 从ProtocolLog创建ProtocolLogParsedResult
/// </summary>
/// <param name="protocolLog">协议日志</param>
/// <param name="index">日志索引</param>
/// <returns>协议日志解析结果</returns>
public static ProtocolLogParsedResult FromProtocolLog(ProtocolLog protocolLog, int? index = null)
{
// 处理时间戳转换
long timestamp;
if (protocolLog.Time.HasValue)
{
// 如果 Time 是秒为单位,转换为毫秒
timestamp = (long)(protocolLog.Time.Value * 1000);
}
else if (protocolLog.Utc.HasValue)
{
// 如果 Utc 是秒为单位,转换为毫秒
timestamp = (long)(protocolLog.Utc.Value * 1000);
}
else
{
// 默认使用当前时间
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
return new ProtocolLogParsedResult
{
MessageId = protocolLog.MessageId,
Index = index,
ProtocolLayer = ProtocolLayerType.NONE, // 需要根据实际内容解析
Message = protocolLog.Message,
MessageData = protocolLog.Headers,
Timestamp = timestamp,
Time = TimeSpan.FromMilliseconds(protocolLog.Time ?? 0),
Direction = DirectionLogsType.Unknown,
ProtocolType = protocolLog.Type ?? string.Empty
};
}
/// <summary>
/// 从ProtocolLogDetail创建ProtocolLogParsedResult
/// </summary>
/// <param name="detail">协议日志明细</param>
/// <param name="index">日志索引</param>
/// <returns>协议日志解析结果</returns>
public static ProtocolLogParsedResult FromProtocolLogDetail(ProtocolLogDetail detail, int? index = null)
{
return new ProtocolLogParsedResult
{
Index = index ?? detail.Idx,
ProtocolLayer = ProtocolLayerTypeExtensions.FromString(detail.Layer),
UeId = detail.UeId,
CellId = detail.Cell,
Info = detail.Src,
MessageData = detail.Data?.ToArray(),
Timestamp = detail.Timestamp,
Time = TimeSpan.FromMilliseconds(detail.Timestamp),
Direction = ParseDirection(detail.Dir),
ProtocolType = detail.Layer
};
}
/// <summary>
/// 解析方向字符串为DirectionLogsType
/// </summary>
/// <param name="direction">方向字符串</param>
/// <returns>方向类型</returns>
private static DirectionLogsType ParseDirection(string? direction)
{
if (string.IsNullOrWhiteSpace(direction))
return DirectionLogsType.Unknown;
return direction.ToLower() switch
{
"up" or "uplink" or "ul" => DirectionLogsType.Uplink,
"down" or "downlink" or "dl" => DirectionLogsType.Downlink,
"bidirectional" or "bi" => DirectionLogsType.Bidirectional,
"internal" or "int" => DirectionLogsType.Internal,
_ => DirectionLogsType.Unknown
};
}
/// <summary>
/// 检查解析结果是否包含有效数据
/// </summary>
/// <returns>是否包含有效数据</returns>
public bool HasValidData()
{
return !string.IsNullOrEmpty(Id) &&
(ProtocolLayer != ProtocolLayerType.NONE || !string.IsNullOrEmpty(ProtocolType));
}
/// <summary>
/// 获取解析结果摘要信息
/// </summary>
/// <returns>摘要信息</returns>
public string GetSummary()
{
return $"ProtocolLogParsed[{Id}] - {ProtocolLayer.GetDisplayName()} - {Direction} - UE:{UeId} - Cell:{CellId}";
}
/// <summary>
/// 创建解析结果的副本
/// </summary>
/// <returns>新的协议日志解析结果</returns>
public ProtocolLogParsedResult Copy()
{
return new ProtocolLogParsedResult
{
Id = Guid.NewGuid().ToString(), // 生成新的ID
Index = Index,
MessageId = MessageId,
ProtocolLayer = ProtocolLayer,
ProtocolType = ProtocolType,
UeId = UeId,
Plmn = Plmn,
Tmsi = Tmsi,
Imei = Imei,
Imsi = Imsi,
CellId = CellId,
Cell = Cell,
Info = Info,
Message = Message,
MessageData = MessageData?.Clone() as string[],
Time = Time,
Timestamp = Timestamp,
Direction = Direction
};
}
/// <summary>
/// 转换为JSON字符串
/// </summary>
/// <returns>JSON字符串</returns>
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
/// <summary>
/// 从JSON字符串创建解析结果
/// </summary>
/// <param name="json">JSON字符串</param>
/// <returns>协议日志解析结果</returns>
public static ProtocolLogParsedResult FromJson(string json)
{
return JsonConvert.DeserializeObject<ProtocolLogParsedResult>(json) ?? new ProtocolLogParsedResult();
}
}

136
CoreAgent.Domain/Models/Protocol/RanLayerLog.cs

@ -0,0 +1,136 @@
using System;
using System.Text.Json.Serialization;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// RAN层日志实体类
/// 该实体用于记录RAN(无线接入网)相关的各层日志信息
/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分
/// </summary>
public class RanLayerLog
{
/// <summary>
/// GTP-U协议层日志级别
/// </summary>
public string GTPU { get; set; }
/// <summary>
/// LPPa协议层日志级别
/// </summary>
public string LPPa { get; set; }
/// <summary>
/// M2AP协议层日志级别
/// </summary>
public string M2AP { get; set; }
/// <summary>
/// MAC协议层日志级别
/// </summary>
public string MAC { get; set; }
/// <summary>
/// NAS协议层日志级别
/// </summary>
public string NAS { get; set; }
/// <summary>
/// NGAP协议层日志级别
/// </summary>
public string NGAP { get; set; }
/// <summary>
/// NRPPa协议层日志级别
/// </summary>
public string NRPPa { get; set; }
/// <summary>
/// PDCP协议层日志级别
/// </summary>
public string PDCP { get; set; }
/// <summary>
/// PHY协议层日志级别
/// </summary>
public string PHY { get; set; }
/// <summary>
/// RLC协议层日志级别
/// </summary>
public string RLC { get; set; }
/// <summary>
/// RRC协议层日志级别
/// </summary>
public string RRC { get; set; }
/// <summary>
/// S1AP协议层日志级别
/// </summary>
public string S1AP { get; set; }
/// <summary>
/// TRX协议层日志级别
/// </summary>
public string TRX { get; set; }
/// <summary>
/// X2AP协议层日志级别
/// </summary>
public string X2AP { get; set; }
/// <summary>
/// XnAP协议层日志级别
/// </summary>
public string XnAP { get; set; }
/// <summary>
/// PROD协议层日志级别
/// </summary>
[JsonIgnore]
public string PROD { get; set; }
/// <summary>
/// 初始化RAN层日志级别
/// </summary>
/// <param name="isNonStandaloneMode">是否为非独立组网模式(NSA模式)</param>
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();
}
/// <summary>
/// 更新指定层的日志级别
/// </summary>
/// <param name="layerName">层名称</param>
/// <param name="logLevel">日志级别</param>
/// <returns>是否更新成功</returns>
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;
}
}

219
CoreAgent.Domain/Models/Protocol/UserNetworkIdentity.cs

@ -0,0 +1,219 @@
using Newtonsoft.Json;
namespace CoreAgent.Domain.Models.Protocol;
/// <summary>
/// 用户网络身份信息
/// 用于存储移动网络用户的基本身份和位置信息
/// 遵循DDD(领域驱动设计)原则,作为领域模型的一部分
/// </summary>
public class UserNetworkIdentity
{
/// <summary>
/// 公共陆地移动网络标识
/// </summary>
[JsonProperty("plmn")]
public string? Plmn { get; set; }
/// <summary>
/// 旧的临时移动用户标识
/// </summary>
[JsonProperty("oldTmsi")]
public string? OldTmsi { get; set; }
/// <summary>
/// 临时移动用户标识
/// </summary>
[JsonProperty("tmsi")]
public string? Tmsi { get; set; }
/// <summary>
/// 国际移动用户标识
/// </summary>
[JsonProperty("imsi")]
public string? Imsi { get; set; }
/// <summary>
/// 小区ID
/// </summary>
[JsonProperty("cellId")]
public int? CellId { get; set; }
/// <summary>
/// 用户设备ID
/// </summary>
[JsonProperty("ueId")]
public int? UeId { get; set; }
/// <summary>
/// 初始化用户网络身份信息的新实例
/// </summary>
public UserNetworkIdentity()
{
}
/// <summary>
/// 初始化用户网络身份信息的新实例
/// </summary>
/// <param name="plmn">公共陆地移动网络标识</param>
/// <param name="oldTmsi">旧的临时移动用户标识</param>
/// <param name="tmsi">临时移动用户标识</param>
/// <param name="imsi">国际移动用户标识</param>
/// <param name="cellId">小区ID</param>
/// <param name="ueId">用户设备ID</param>
public UserNetworkIdentity(
string? plmn = null,
string? oldTmsi = null,
string? tmsi = null,
string? imsi = null,
int? cellId = null,
int? ueId = null)
{
Plmn = plmn;
OldTmsi = oldTmsi;
Tmsi = tmsi;
Imsi = imsi;
CellId = cellId;
UeId = ueId;
}
/// <summary>
/// 检查是否包含有效的用户身份信息
/// </summary>
/// <returns>是否包含有效信息</returns>
public bool HasValidIdentity()
{
return !string.IsNullOrWhiteSpace(Imsi) ||
!string.IsNullOrWhiteSpace(Tmsi) ||
UeId.HasValue;
}
/// <summary>
/// 检查是否包含位置信息
/// </summary>
/// <returns>是否包含位置信息</returns>
public bool HasLocationInfo()
{
return !string.IsNullOrWhiteSpace(Plmn) || CellId.HasValue;
}
/// <summary>
/// 获取用户身份摘要信息
/// </summary>
/// <returns>摘要信息</returns>
public string GetIdentitySummary()
{
var parts = new List<string>();
if (!string.IsNullOrWhiteSpace(Imsi))
parts.Add($"IMSI:{Imsi}");
if (!string.IsNullOrWhiteSpace(Tmsi))
parts.Add($"TMSI:{Tmsi}");
if (UeId.HasValue)
parts.Add($"UE:{UeId}");
if (!string.IsNullOrWhiteSpace(Plmn))
parts.Add($"PLMN:{Plmn}");
if (CellId.HasValue)
parts.Add($"Cell:{CellId}");
return parts.Count > 0 ? string.Join(" | ", parts) : "No Identity Info";
}
/// <summary>
/// 检查TMSI是否发生变化
/// </summary>
/// <returns>TMSI是否发生变化</returns>
public bool HasTmsiChanged()
{
return !string.IsNullOrWhiteSpace(OldTmsi) &&
!string.IsNullOrWhiteSpace(Tmsi) &&
!OldTmsi.Equals(Tmsi, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// 获取TMSI变化信息
/// </summary>
/// <returns>TMSI变化信息</returns>
public string GetTmsiChangeInfo()
{
if (HasTmsiChanged())
{
return $"TMSI Changed: {OldTmsi} -> {Tmsi}";
}
return "TMSI Unchanged";
}
/// <summary>
/// 创建用户网络身份信息的副本
/// </summary>
/// <returns>新的用户网络身份信息</returns>
public UserNetworkIdentity Copy()
{
return new UserNetworkIdentity
{
Plmn = Plmn,
OldTmsi = OldTmsi,
Tmsi = Tmsi,
Imsi = Imsi,
CellId = CellId,
UeId = UeId
};
}
/// <summary>
/// 更新TMSI信息
/// </summary>
/// <param name="newTmsi">新的TMSI</param>
public void UpdateTmsi(string? newTmsi)
{
if (!string.IsNullOrWhiteSpace(Tmsi))
{
OldTmsi = Tmsi;
}
Tmsi = newTmsi;
}
/// <summary>
/// 转换为JSON字符串
/// </summary>
/// <returns>JSON字符串</returns>
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
/// <summary>
/// 从JSON字符串创建用户网络身份信息
/// </summary>
/// <param name="json">JSON字符串</param>
/// <returns>用户网络身份信息</returns>
public static UserNetworkIdentity FromJson(string json)
{
return JsonConvert.DeserializeObject<UserNetworkIdentity>(json) ?? new UserNetworkIdentity();
}
/// <summary>
/// 合并另一个用户网络身份信息
/// </summary>
/// <param name="other">另一个用户网络身份信息</param>
/// <returns>合并后的用户网络身份信息</returns>
public UserNetworkIdentity Merge(UserNetworkIdentity other)
{
if (other == null)
return this;
return new UserNetworkIdentity
{
Plmn = Plmn ?? other.Plmn,
OldTmsi = OldTmsi ?? other.OldTmsi,
Tmsi = Tmsi ?? other.Tmsi,
Imsi = Imsi ?? other.Imsi,
CellId = CellId ?? other.CellId,
UeId = UeId ?? other.UeId
};
}
}

9
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<CellularNetworkContext> _logger;
private NetworkLayerLogs _networkLogs;
/// <summary>
/// 获取取消令牌源
@ -44,6 +46,11 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable
/// </summary>
public NetworkConfigType CurrentConfigType => _currentConfigType;
/// <summary>
/// 网络层日志配置
/// </summary>
public NetworkLayerLogs NetworkLogs => _networkLogs;
public CellularNetworkContext(
IOptions<NetworkCommandConfig> networkCommandConfig,
IOptions<AppSettings> 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();
}
/// <summary>
@ -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)

2
CoreAgent.Infrastructure/CoreAgent.Infrastructure.csproj

@ -15,11 +15,13 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="WebSocket4Net" Version="0.15.2" />
</ItemGroup>
<ItemGroup>

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

143
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<string> _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<string>();
_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);
}
}
}

12
CoreAgent.Infrastructure/Services/Network/NetworkInterfaceManager.cs

@ -244,7 +244,8 @@ public class NetworkInterfaceManager : INetworkInterfaceManager
var fullCommand = $"{command} {NULL_CONFIG} {config.CoreNetworkConfig} {config.ImsConfig}";
_logger.LogInformation("并发执行次要配置启动命令: {Command}", fullCommand);
secondaryTasks.Add(_commandExecutor.ExecuteCommandAsync(fullCommand, _context.TokenSource));
//new CancellationTokenSource()
secondaryTasks.Add(_commandExecutor.ExecuteCommandAsync(fullCommand, new CancellationTokenSource()));
}
// 等待所有次要配置命令执行完成
@ -263,7 +264,8 @@ public class NetworkInterfaceManager : INetworkInterfaceManager
var fullCommand = $"{command} {networkConfig.RagConfig} {config.CoreNetworkConfig} {config.ImsConfig}";
_logger.LogInformation("执行单配置启动命令: {Command}", fullCommand);
var result = await _commandExecutor.ExecuteCommandAsync(fullCommand, _context.TokenSource);
//_context.TokenSource
var result = await _commandExecutor.ExecuteCommandAsync(fullCommand, new CancellationTokenSource());
return result.IsSuccess
? NetworkInterfaceOperationResult.Success(NetworkConfigType.BothRagAndCore)
: NetworkInterfaceOperationResult.Failure($"执行单配置启动命令失败: {result.Error}", NetworkConfigType.BothRagAndCore);
@ -282,7 +284,8 @@ public class NetworkInterfaceManager : INetworkInterfaceManager
var fullCommand = $"{command} NULL {config.CoreNetworkConfig} {config.ImsConfig}";
_logger.LogInformation("并发执行次要配置启动命令: {Command}", fullCommand);
secondaryTasks.Add(_commandExecutor.ExecuteCommandAsync(fullCommand, _context.TokenSource));
//_context.TokenSource
secondaryTasks.Add(_commandExecutor.ExecuteCommandAsync(fullCommand, new CancellationTokenSource()));
}
// 等待所有次要配置命令执行完成
@ -300,7 +303,8 @@ public class NetworkInterfaceManager : INetworkInterfaceManager
var fullCommand = $"{primaryCommand} {networkConfig.RagConfig} {primaryConfig.CoreNetworkConfig} {primaryConfig.ImsConfig}";
_logger.LogInformation("执行主配置启动命令: {Command}", fullCommand);
var result = await _commandExecutor.ExecuteCommandAsync(fullCommand, _context.TokenSource);
//_context.TokenSource
var result = await _commandExecutor.ExecuteCommandAsync(fullCommand, new CancellationTokenSource());
if (!result.IsSuccess)
{
return NetworkInterfaceOperationResult.Failure($"主配置命令执行失败: {result.Error}", NetworkConfigType.BothRagAndCore);

256
CoreAgent.Infrastructure/Services/ProtocolLogHandlers/IMSLogMessageHandler.cs

@ -0,0 +1,256 @@
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
{
/// <summary>
/// IMS协议消息处理器
/// 负责处理IMS相关的WebSocket消息,包括用户更新、短信、邀请等功能
/// </summary>
public class IMSLogMessageHandler : ICustomMessageHandler, IDisposable
{
private readonly ILogger _logger;
private int _messageId = 0;
private string _currentMessageId = string.Empty;
private readonly Action<string> _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<string> 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)
{
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)
{
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)
{
string statsResponse = CreateStatsMessage();
_logger.LogInformation("发送stats响应: {Response}", statsResponse);
await Task.Run(() => observer.SendMessage(statsResponse));
}
private string CreateMessage(string message)
{
return JObject.FromObject(new { message, message_id = Interlocked.Increment(ref _messageId) }).ToString();
}
private JObject CreateRegisterMessage(string register)
{
return JObject.FromObject(new { message = "register", message_id = Interlocked.Increment(ref _messageId), register });
}
private string CreateStatsMessage()
{
return CreateMessage("stats");
}
private JObject SettingBaseLayerLogslevel(JObject keyValues, bool isCloseSystemInfo = false)
{
keyValues.Remove("rotate");
keyValues.Remove("path");
keyValues.Remove("count");
keyValues["bcch"] = isCloseSystemInfo;
return JObject.FromObject(new
{
message = "config_set",
logs = keyValues,
message_id = Interlocked.Increment(ref _messageId)
});
}
private string LayerLogslevelSetting(bool isHead = false)
{
BaseNetworkLog<ImsLayerLog> logtype = new BaseNetworkLog<ImsLayerLog>
{
Timeout = isHead ? 0 : 1,
MinLogCount = 64,
MaxLogCount = 2048,
LayerConfig = _context.NetworkLogs.ImsLog,
Message = "log_get",
IncludeHeaders = isHead,
MessageId = Interlocked.Increment(ref _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);
}
}
}

147
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
{
/// <summary>
/// 协议日志提供者观察者
/// 负责接收、缓存和转发协议日志数据
/// 使用生产者-消费者模式处理日志数据流
/// </summary>
public class ProtocolLogsProviderObserver : IProtocolLogsProviderObserver
{
/// <summary>
/// 用于存储待处理的协议日志消息的阻塞队列
/// </summary>
private readonly static BlockingCollection<string> BlockingQueue = new BlockingCollection<string>();
/// <summary>
/// 日志记录器
/// </summary>
private readonly ILogger logger;
/// <summary>
/// 网络上下文,用于检查网络状态
/// </summary>
private readonly CellularNetworkContext networkContext;
/// <summary>
/// 初始化协议日志提供者观察者
/// </summary>
/// <param name="networkContext">网络上下文</param>
/// <param name="logger">日志记录器</param>
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("消费者任务已启动");
}
/// <summary>
/// 接收并处理新的协议日志数据
/// </summary>
/// <param name="msg">协议日志消息</param>
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);
}
}
/// <summary>
/// 生产者方法:将消息添加到阻塞队列中
/// </summary>
/// <param name="message">要添加的消息</param>
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;
}
}
/// <summary>
/// 消费者方法:从队列中获取并处理消息
/// </summary>
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("消费者任务已结束");
}
}
}
}

30
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()
{
}
}
}

12
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
{
}
}

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

30
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()
{
}
}
}

83
CoreAgent.Infrastructure/Services/ProtocolLogHandlers/ProtocolRanParesHandleLogs.cs

@ -0,0 +1,83 @@
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<ProtocolLogDetail[]>();
var parseResultData = LogParsedResultHandle(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());
}
}
public ProtocolLogParsedResult[] LogParsedResultHandle(ProtocolLogDetail[] logDetails, int MessageId)
{
List<ProtocolLogParsedResult> parsedResults = new List<ProtocolLogParsedResult>();
return parsedResults.ToArray();
}
public void LogListParse(ProtocolLogDetail[] list)
{
int length = list.Length;
for (int i = 0; i < length; i++)
{
var log= list[i];
switch (log.Layer)
{
case "PHY":
break;
case "MAC":
break;
case "RRC":
break;
case "NAS":
break;
default:
break;
}
}
}
}
}

362
CoreAgent.Infrastructure/Services/ProtocolLogHandlers/RanLogMessageHandler.cs

@ -0,0 +1,362 @@
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
{
/// <summary>
/// RAN协议WebSocket消息处理器
/// 负责处理无线接入网(RAN)相关的WebSocket消息,包括配置获取、日志获取等功能
/// </summary>
public class RanLogMessageHandler : ICustomMessageHandler, IDisposable
{
private readonly ILogger _logger;
private int _messageId = 0;
private string _currentMessageId = string.Empty;
private readonly Action<string> _messageCallback;
private readonly ICellularNetworkContext _networkContext;
private readonly BlockingCollection<(string MessageData, IObserverCustomWebSocketClient Observer)> _messageQueue;
private readonly CancellationTokenSource _cancellationTokenSource;
private readonly Task _processTask;
private bool _disposed;
/// <summary>
/// 初始化RAN协议消息处理器
/// </summary>
/// <param name="logger">日志记录器</param>
/// <param name="context">蜂窝网络上下文</param>
/// <param name="action">消息回调处理函数</param>
public RanLogMessageHandler(ILogger logger, ICellularNetworkContext context, Action<string> 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协议消息处理器初始化完成,消息队列已启动");
}
/// <summary>
/// 处理接收到的WebSocket消息
/// 将消息加入处理队列,由队列处理器异步处理
/// </summary>
/// <param name="messageData">接收到的消息数据</param>
/// <param name="observer">WebSocket客户端观察者</param>
public void HandleMessage(string messageData, IObserverCustomWebSocketClient observer)
{
try
{
_logger.LogDebug("将消息加入处理队列: {MessageData}", messageData);
_messageQueue.Add((messageData, observer));
}
catch (Exception ex)
{
_logger.LogError(ex, "将消息加入队列时发生错误: {MessageData}", messageData);
}
}
/// <summary>
/// 处理消息队列中的消息
/// 持续从队列中获取消息并处理,直到队列关闭或取消
/// </summary>
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, "消息队列处理过程中发生错误");
}
}
/// <summary>
/// 处理单条消息
/// 解析消息类型并分发到对应的处理方法
/// </summary>
/// <param name="messageData">消息数据</param>
/// <param name="observer">WebSocket客户端观察者</param>
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);
}
}
/// <summary>
/// 根据消息类型分发到对应的处理方法
/// </summary>
/// <param name="messageType">消息类型</param>
/// <param name="data">消息数据</param>
/// <param name="observer">WebSocket客户端观察者</param>
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;
}
}
/// <summary>
/// 处理ready消息
/// 发送config_get请求,准备获取配置信息
/// </summary>
/// <param name="observer">WebSocket客户端观察者</param>
private async Task HandleReadyMessageAsync(IObserverCustomWebSocketClient observer)
{
string readyResponse = JObject.FromObject(new { message = "config_get", message_id = Interlocked.Increment(ref _messageId) }).ToString();
_logger.LogInformation("发送ready响应: {Response}", readyResponse);
await Task.Run(() => observer.SendMessage(readyResponse));
_currentMessageId = _messageId.ToString();
}
/// <summary>
/// 处理config_get消息
/// 发送统计信息和基础层日志配置
/// </summary>
/// <param name="data">消息数据</param>
/// <param name="observer">WebSocket客户端观察者</param>
private async Task HandleConfigGetMessageAsync(JObject data, IObserverCustomWebSocketClient observer)
{
if (_currentMessageId == data["message_id"]!.ToString())
{
_logger.LogInformation("处理config_get请求");
var responseArray = new JArray();
var statsConfig = new { message = "stats", message_id = Interlocked.Increment(ref _messageId), rf = false, samples = false };
responseArray.Add(JObject.FromObject(statsConfig));
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);
}
}
/// <summary>
/// 处理config_set消息
/// 发送层日志配置
/// </summary>
/// <param name="observer">WebSocket客户端观察者</param>
private async Task HandleConfigSetMessageAsync(IObserverCustomWebSocketClient observer)
{
string configResponse = ConfigureLayerLogs(true);
await Task.Run(() => observer.SendMessage(configResponse));
_currentMessageId = _messageId.ToString();
_logger.LogInformation("发送config_set响应: {Response}", configResponse);
}
/// <summary>
/// 处理log_get消息
/// 发送日志配置并触发回调
/// </summary>
/// <param name="data">消息数据</param>
/// <param name="observer">WebSocket客户端观察者</param>
private async Task HandleLogGetMessageAsync(JObject data, IObserverCustomWebSocketClient observer)
{
if (_currentMessageId == data["message_id"]!.ToString())
{
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()));
}
/// <summary>
/// 处理stats消息
/// 发送统计信息请求
/// </summary>
/// <param name="observer">WebSocket客户端观察者</param>
private async Task HandleStatsMessageAsync(IObserverCustomWebSocketClient observer)
{
string statsResponse = JObject.FromObject(new
{
message = "stats",
message_id = Interlocked.Increment(ref _messageId),
rf = false,
samples = false
}).ToString();
await Task.Run(() => observer.SendMessage(statsResponse));
_logger.LogInformation("发送stats响应: {Response}", statsResponse);
}
/// <summary>
/// 配置基础层日志
/// 设置各种日志级别的开关状态
/// </summary>
/// <param name="keyValues">配置键值对</param>
/// <param name="isCloseSystemInfo">是否关闭系统信息</param>
/// <returns>配置后的JSON字符串</returns>
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 = Interlocked.Increment(ref _messageId),
};
string response = JObject.FromObject(configMessage).ToString();
_logger.LogInformation("基础层日志配置完成: {Response}", response);
return response;
}
/// <summary>
/// 配置层日志
/// 设置日志超时、计数等参数
/// </summary>
/// <param name="includeHeaders">是否包含头部信息</param>
/// <returns>配置后的JSON字符串</returns>
private string ConfigureLayerLogs(bool includeHeaders = false)
{
_logger.LogDebug("开始配置层日志: IncludeHeaders={IncludeHeaders}", includeHeaders);
var logConfig = new BaseNetworkLog<RanLayerLog>
{
Timeout = includeHeaders ? 0 : 1,
MinLogCount = 64,
MaxLogCount = 2048,
LayerConfig = _networkContext.NetworkLogs.RanLog,
Message = "log_get",
IncludeHeaders = includeHeaders,
MessageId = Interlocked.Increment(ref _messageId),
};
string response = JObject.FromObject(logConfig).ToString();
_logger.LogInformation("层日志配置完成: {Response}", response);
return response;
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 释放资源的具体实现
/// </summary>
/// <param name="disposing">是否正在释放托管资源</param>
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;
}
}
/// <summary>
/// 析构函数
/// </summary>
~RanLogMessageHandler()
{
Dispose(false);
}
}
}
Loading…
Cancel
Save