diff --git a/CoreAgent.API/Program.cs b/CoreAgent.API/Program.cs index c82418f..1eacf35 100644 --- a/CoreAgent.API/Program.cs +++ b/CoreAgent.API/Program.cs @@ -1,5 +1,4 @@ using CoreAgent.API; -using CoreAgent.Domain.Contexts; using CoreAgent.Domain.Interfaces.Network; using CoreAgent.Domain.Models.System; using CoreAgent.Infrastructure.Logging; diff --git a/CoreAgent.API/Startup.cs b/CoreAgent.API/Startup.cs index 666cc0e..e8a0f51 100644 --- a/CoreAgent.API/Startup.cs +++ b/CoreAgent.API/Startup.cs @@ -3,7 +3,6 @@ using Serilog; using CoreAgent.Infrastructure.Extensions.Logging; using CoreAgent.Infrastructure.Extensions.ServiceCollection; using CoreAgent.Infrastructure.Middleware.GlobalException; -using CoreAgent.Domain.Contexts; using CoreAgent.Domain.Models.System; using Microsoft.Extensions.Configuration; using CoreAgent.Domain.Interfaces.Network; diff --git a/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs b/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs index 333121a..05db761 100644 --- a/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs +++ b/CoreAgent.Domain/Interfaces/Network/ICellularNetworkContext.cs @@ -8,6 +8,8 @@ namespace CoreAgent.Domain.Interfaces.Network; /// public interface ICellularNetworkContext { + #region 基础属性 + /// /// 获取取消令牌源 /// @@ -18,12 +20,35 @@ public interface ICellularNetworkContext /// bool IsInitialized { get; } + /// + /// 网络IP端点管理器 + /// + INetworkIPEndPointManager NetworkIPEndPointManager { get; } + + #endregion + + #region 生命周期管理 + /// /// 初始化上下文 /// /// 网络配置键 void Initialize(string neConfigKey); + /// + /// 重置上下文状态 + /// + void Reset(); + + /// + /// 取消操作 + /// + void Cancel(); + + #endregion + + #region 网络配置管理 + /// /// 获取网络命令配置 /// @@ -35,6 +60,15 @@ public interface ICellularNetworkContext /// string GetNeConfigKey(); + /// + /// 获取应用设置 + /// + AppSettings GetAppSettings(); + + #endregion + + #region 命令管理 + /// /// 获取指定类型的命令配置 /// @@ -48,24 +82,15 @@ public interface ICellularNetworkContext /// 命令类型数组 NetworkCommandType[] GetCommandTypes(); + #endregion + + #region 状态管理 + /// /// 获取网络状态 /// /// 网络状态 CellularNetworkState GetNetworkState(); - /// - /// 重置上下文状态 - /// - void Reset(); - - /// - /// 取消操作 - /// - void Cancel(); - - /// - /// 获取应用设置 - /// - AppSettings GetAppSettings(); + #endregion } \ No newline at end of file diff --git a/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs b/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs index 196723b..d49200b 100644 --- a/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs +++ b/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs @@ -16,4 +16,11 @@ public interface INetworkConfigCopier /// 应用设置 /// 复制结果 Task CopyConfigValuesToTempAsync(NetworkConfiguration networkConfig, AppSettings appSettings); + + /// + /// 获取所有配置文件的 IP 端点信息 + /// + /// 网络配置 + /// (EndPoints: IP 端点信息集合, HasAnyEndPoint: 是否成功获取到任何端点信息) + Task<(NetworkIPEndPoints EndPoints, bool HasAnyEndPoint)> GetComAddrInfoAsync(NetworkConfiguration networkConfig); } \ No newline at end of file diff --git a/CoreAgent.Domain/Interfaces/Network/INetworkIPEndPointManager.cs b/CoreAgent.Domain/Interfaces/Network/INetworkIPEndPointManager.cs new file mode 100644 index 0000000..4514488 --- /dev/null +++ b/CoreAgent.Domain/Interfaces/Network/INetworkIPEndPointManager.cs @@ -0,0 +1,35 @@ +using CoreAgent.Domain.Models.Network; + +namespace CoreAgent.Domain.Interfaces.Network; + +/// +/// 网络 IP 端点管理器接口 +/// +public interface INetworkIPEndPointManager +{ + /// + /// 更新 IP 端点信息 + /// + /// IP 端点信息集合 + void UpdateEndPoints(NetworkIPEndPoints endPoints); + + /// + /// 获取 RAN 端点信息 + /// + RanIPEndPoint GetRanEndPoint(); + + /// + /// 获取 CN 端点列表 + /// + List GetCnEndPoints(); + + /// + /// 获取 IMS 端点列表 + /// + List GetImsEndPoints(); + + /// + /// 清除所有端点信息 + /// + void Clear(); +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Network/CnIPEndPoint.cs b/CoreAgent.Domain/Models/Network/CnIPEndPoint.cs new file mode 100644 index 0000000..341a105 --- /dev/null +++ b/CoreAgent.Domain/Models/Network/CnIPEndPoint.cs @@ -0,0 +1,9 @@ +namespace CoreAgent.Domain.Models.Network; + +/// +/// CN网络IP端点模型 +/// +public class CnIPEndPoint : NetworkIPEndPoint +{ + // CN特有的属性 +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Network/ImsIPEndPoint.cs b/CoreAgent.Domain/Models/Network/ImsIPEndPoint.cs new file mode 100644 index 0000000..1267979 --- /dev/null +++ b/CoreAgent.Domain/Models/Network/ImsIPEndPoint.cs @@ -0,0 +1,9 @@ +namespace CoreAgent.Domain.Models.Network; + +/// +/// IMS网络IP端点模型 +/// +public class ImsIPEndPoint : NetworkIPEndPoint +{ + // IMS特有的属性 +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Network/NetworkIPEndPoint.cs b/CoreAgent.Domain/Models/Network/NetworkIPEndPoint.cs new file mode 100644 index 0000000..6912c04 --- /dev/null +++ b/CoreAgent.Domain/Models/Network/NetworkIPEndPoint.cs @@ -0,0 +1,17 @@ +namespace CoreAgent.Domain.Models.Network; + +/// +/// 网络IP端点基础模型 +/// +public class NetworkIPEndPoint +{ + /// + /// PLMN标识 + /// + public string Plmn { get; set; } + + /// + /// 通信地址 + /// + public string ComAddr { get; set; } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Network/NetworkIPEndPoints.cs b/CoreAgent.Domain/Models/Network/NetworkIPEndPoints.cs new file mode 100644 index 0000000..b5545de --- /dev/null +++ b/CoreAgent.Domain/Models/Network/NetworkIPEndPoints.cs @@ -0,0 +1,22 @@ +namespace CoreAgent.Domain.Models.Network; + +/// +/// 网络 IP 端点集合 +/// +public class NetworkIPEndPoints +{ + /// + /// IMS 网络 IP 端点列表 + /// + public List ImsEndPoints { get; set; } = new(); + + /// + /// 核心网络 IP 端点列表 + /// + public List CnEndPoints { get; set; } = new(); + + /// + /// RAN 网络 IP 端点 + /// + public RanIPEndPoint RanEndPoint { get; set; } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/Network/RanIPEndPoint.cs b/CoreAgent.Domain/Models/Network/RanIPEndPoint.cs new file mode 100644 index 0000000..6ccfab9 --- /dev/null +++ b/CoreAgent.Domain/Models/Network/RanIPEndPoint.cs @@ -0,0 +1,17 @@ +namespace CoreAgent.Domain.Models.Network; + +/// +/// RAN 网络 IP 端点信息 +/// +public class RanIPEndPoint +{ + /// + /// 通信地址 + /// + public string ComAddr { get; set; } + + /// + /// PLMN 列表 + /// + public List Plmns { get; set; } = new(); +} \ No newline at end of file diff --git a/CoreAgent.Domain/Contexts/CellularNetworkContext.cs b/CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs similarity index 90% rename from CoreAgent.Domain/Contexts/CellularNetworkContext.cs rename to CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs index 2dc67c4..b799e53 100644 --- a/CoreAgent.Domain/Contexts/CellularNetworkContext.cs +++ b/CoreAgent.Infrastructure/Contexts/CellularNetworkContext.cs @@ -1,9 +1,10 @@ +using CoreAgent.Domain.Interfaces; using CoreAgent.Domain.Interfaces.Network; using CoreAgent.Domain.Models.Network; using CoreAgent.Domain.Models.System; using Microsoft.Extensions.Options; -namespace CoreAgent.Domain.Contexts; +namespace CoreAgent.Infrastructure.Contexts; /// /// 蜂窝网络领域上下文 @@ -18,6 +19,7 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable private CancellationTokenSource _token; private bool _isDisposed; private bool _isInitialized; + private readonly INetworkIPEndPointManager _networkIPEndPointManager; /// /// 获取取消令牌源 @@ -29,15 +31,22 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable /// public bool IsInitialized => _isInitialized; + /// + /// 网络IP端点管理器 + /// + public INetworkIPEndPointManager NetworkIPEndPointManager => _networkIPEndPointManager; + public CellularNetworkContext( IOptions networkCommandConfig, - IOptions appSettings) + IOptions appSettings, + INetworkIPEndPointManager networkIPEndPointManager) { _isDisposed = false; _isInitialized = false; _token = new CancellationTokenSource(); _networkCommandConfig = networkCommandConfig?.Value ?? throw new ArgumentNullException(nameof(networkCommandConfig)); _appSettings = appSettings?.Value ?? throw new ArgumentNullException(nameof(appSettings)); + _networkIPEndPointManager = networkIPEndPointManager ?? throw new ArgumentNullException(nameof(networkIPEndPointManager)); } /// @@ -63,6 +72,7 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable lock (_lock) { + _networkIPEndPointManager.Clear(); _neConfigKey = neConfigKey; _networkState = new CellularNetworkState(_neConfigKey); _isInitialized = true; @@ -181,6 +191,7 @@ public class CellularNetworkContext : ICellularNetworkContext, IDisposable _neConfigKey = string.Empty; _isInitialized = false; _networkState = new CellularNetworkState(string.Empty); + _networkIPEndPointManager.Clear(); } } diff --git a/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs b/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs index 1b082df..9e68ce1 100644 --- a/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs +++ b/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs @@ -1,8 +1,9 @@ -using CoreAgent.Domain.Contexts; + using CoreAgent.Domain.Interfaces; using CoreAgent.Domain.Interfaces.Network; using CoreAgent.Domain.Interfaces.System.Command; using CoreAgent.Infrastructure.Command.Factories; +using CoreAgent.Infrastructure.Contexts; using CoreAgent.Infrastructure.Repositories; using CoreAgent.Infrastructure.Services; using CoreAgent.Infrastructure.Services.Network; @@ -22,6 +23,7 @@ public static class CommandServiceExtensions /// 服务集合 public static IServiceCollection AddCommandCustomService(this IServiceCollection services) { + services.AddSingleton(); services.AddSingleton(); // 注册命令执行器工厂 services.AddSingleton(); diff --git a/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs b/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs index 79d1d21..75352ea 100644 --- a/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs +++ b/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs @@ -1,5 +1,4 @@ using CliWrap; -using CoreAgent.Domain.Contexts; using CoreAgent.Domain.Entities; using CoreAgent.Domain.Interfaces; using CoreAgent.Domain.Interfaces.Network; @@ -24,12 +23,8 @@ public class CellularNetworkService : ICellularNetworkService private readonly INetworkConfigCopier _configCopier; private readonly INetworkInterfaceManager _interfaceManager; private static readonly SemaphoreSlim _startLock = new(1, 1); - private const int MaxConnectionAttempts = 30; - private const int ConnectionCheckDelayMs = 1000; - private const int LockTimeoutSeconds = 5; - private const string NULL_CONFIG = "NULL"; - private const string KILL_COMMAND_TEMPLATE = "ps -ef | grep {0} | grep -v grep | awk '{{print $2}}' | xargs kill -9"; - private const string COM_ADDR_TEMPLATE = "cat {0} | grep com_addr | awk -F'\"' '{{print $4}}'"; + private const int LockTimeoutSeconds = 60; + public CellularNetworkService( ILogger logger, @@ -223,7 +218,19 @@ public class CellularNetworkService : ICellularNetworkService return CellularNetworkOperationResult.Failure(message); } - // 4. 启动网络配置 + // 4. 获取 IP 端点信息 + var (endPoints, hasAnyEndPoint) = await _configCopier.GetComAddrInfoAsync(config); + if (!hasAnyEndPoint) + { + var message = "未获取到任何有效的 IP 端点信息"; + _logger.LogError(message); + return CellularNetworkOperationResult.Failure(message); + } + + // 5. 更新 IP 端点管理器 + _context.NetworkIPEndPointManager.UpdateEndPoints(endPoints); + + // 6. 启动网络配置 _logger.LogInformation("正在启动蜂窝网络配置: {ConfigKey}", key); var enableResult = await _interfaceManager.EnableAsync(config); if (!enableResult.IsSuccess) @@ -233,7 +240,7 @@ public class CellularNetworkService : ICellularNetworkService return CellularNetworkOperationResult.Failure(message); } - // 5. 更新状态 + // 7. 更新状态 var state = _context.GetNetworkState(); state.MarkAsStarted(); _logger.LogInformation("蜂窝网络配置 {ConfigKey} 启动成功", key); diff --git a/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs b/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs index 4f9342f..9cb24ab 100644 --- a/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs +++ b/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs @@ -16,6 +16,7 @@ public class NetworkConfigCopier : INetworkConfigCopier private readonly ILogger _logger; private readonly ISystemCommandExecutor _commandExecutor; private const string COM_ADDR_TEMPLATE = "cat {0} | grep com_addr | awk -F'\"' '{{print $4}}'"; + private const string PLMN_TEMPLATE = "cat {0} | grep plmn | awk -F'\"' '{{print $4}}'"; public NetworkConfigCopier( ILogger logger, @@ -38,13 +39,6 @@ public class NetworkConfigCopier : INetworkConfigCopier // 复制 RAG 配置文件 if (!string.IsNullOrEmpty(networkConfig.RagConfig)) { - // 获取com_addr值 - var (isSuccess, comAddr, errorMessage) = await GetComAddrValueAsync(networkConfig.RagConfig, "RAG"); - if (!isSuccess) - { - return NetworkConfigCopyResult.Failure($"RAG配置文件验证失败: {errorMessage}"); - } - if (!CopyConfigFile(networkConfig.RagConfig, appSettings.RanConfigDirectory, path => networkConfig.RagConfig = path, "RAG")) { @@ -57,13 +51,6 @@ public class NetworkConfigCopier : INetworkConfigCopier { if (!string.IsNullOrEmpty(config.CoreNetworkConfig)) { - // 获取CN com_addr值 - var (isSuccess, comAddr, errorMessage) = await GetComAddrValueAsync(config.CoreNetworkConfig, "CN"); - if (!isSuccess) - { - return NetworkConfigCopyResult.Failure($"CN配置文件验证失败: {errorMessage}"); - } - if (!CopyConfigFile(config.CoreNetworkConfig, appSettings.MmeConfigDirectory, path => config.CoreNetworkConfig = path, "核心网络")) { @@ -73,13 +60,6 @@ public class NetworkConfigCopier : INetworkConfigCopier if (!string.IsNullOrEmpty(config.ImsConfig)) { - // 获取IMS com_addr值 - var (isSuccess, comAddr, errorMessage) = await GetComAddrValueAsync(config.ImsConfig, "IMS"); - if (!isSuccess) - { - return NetworkConfigCopyResult.Failure($"IMS配置文件验证失败: {errorMessage}"); - } - if (!CopyConfigFile(config.ImsConfig, appSettings.MmeConfigDirectory, path => config.ImsConfig = path, "IMS")) { @@ -132,6 +112,48 @@ public class NetworkConfigCopier : INetworkConfigCopier } } + /// + /// 获取配置文件中的 plmn 值 + /// + private async Task<(bool IsSuccess, List Plmns, string ErrorMessage)> GetPlmnValuesAsync(string configPath, string configType) + { + if (string.IsNullOrEmpty(configPath)) + { + return (false, null, $"{configType}配置文件路径为空"); + } + + if (!File.Exists(configPath)) + { + return (false, null, $"{configType}配置文件不存在: {configPath}"); + } + + var result = await _commandExecutor.ExecuteCommandAsync( + string.Format(PLMN_TEMPLATE, configPath), + new CancellationTokenSource()); + + if (result.IsSuccess) + { + var plmns = result.Output + .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .Select(p => p.Trim()) + .Where(p => !string.IsNullOrEmpty(p)) + .Distinct() + .ToList(); + + if (plmns.Count == 0) + { + return (false, null, $"{configType}配置文件中未找到 plmn 值"); + } + + _logger.LogInformation("获取到{ConfigType} plmn值: {Plmns}", configType, string.Join(", ", plmns)); + return (true, plmns, null); + } + else + { + return (false, null, $"获取{configType} plmn值失败: {result.Error}"); + } + } + private void EnsureDirectoriesExist(AppSettings appSettings) { if (!Directory.Exists(appSettings.TempDirectory)) @@ -177,4 +199,74 @@ public class NetworkConfigCopier : INetworkConfigCopier return true; } + + /// + /// 获取所有配置文件的 IP 端点信息 + /// + /// 网络配置 + /// (EndPoints: IP 端点信息集合, HasAnyEndPoint: 是否成功获取到任何端点信息) + public async Task<(NetworkIPEndPoints EndPoints, bool HasAnyEndPoint)> GetComAddrInfoAsync(NetworkConfiguration networkConfig) + { + var endPoints = new NetworkIPEndPoints(); + bool hasAnyEndPoint = false; + + try + { + // 获取 RAN com_addr 和 plmn + if (!string.IsNullOrEmpty(networkConfig.RagConfig)) + { + var (isSuccess, comAddr, _) = await GetComAddrValueAsync(networkConfig.RagConfig, "RAG"); + var (plmnSuccess, plmns, _) = await GetPlmnValuesAsync(networkConfig.RagConfig, "RAG"); + + if (isSuccess && plmnSuccess) + { + endPoints.RanEndPoint = new RanIPEndPoint + { + ComAddr = comAddr, + Plmns = plmns + }; + hasAnyEndPoint = true; + } + } + + // 获取 CN 和 IMS com_addr + foreach (var config in networkConfig.CoreOrImsConfigs) + { + if (!string.IsNullOrEmpty(config.CoreNetworkConfig)) + { + var (isSuccess, comAddr, _) = await GetComAddrValueAsync(config.CoreNetworkConfig, "CN"); + if (isSuccess) + { + endPoints.CnEndPoints.Add(new CnIPEndPoint + { + ComAddr = comAddr, + Plmn = config.Plmn + }); + hasAnyEndPoint = true; + } + } + + if (!string.IsNullOrEmpty(config.ImsConfig)) + { + var (isSuccess, comAddr, _) = await GetComAddrValueAsync(config.ImsConfig, "IMS"); + if (isSuccess) + { + endPoints.ImsEndPoints.Add(new ImsIPEndPoint + { + ComAddr = comAddr, + Plmn = config.Plmn + }); + hasAnyEndPoint = true; + } + } + } + + return (EndPoints: endPoints, HasAnyEndPoint: hasAnyEndPoint); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取 IP 端点信息时发生错误"); + return (EndPoints: endPoints, HasAnyEndPoint: false); + } + } } \ No newline at end of file diff --git a/CoreAgent.Infrastructure/Services/Network/NetworkIPEndPointManager.cs b/CoreAgent.Infrastructure/Services/Network/NetworkIPEndPointManager.cs new file mode 100644 index 0000000..aaf3fe4 --- /dev/null +++ b/CoreAgent.Infrastructure/Services/Network/NetworkIPEndPointManager.cs @@ -0,0 +1,116 @@ +using CoreAgent.Domain.Interfaces.Network; +using CoreAgent.Domain.Models.Network; +using Microsoft.Extensions.Logging; + +namespace CoreAgent.Infrastructure.Services.Network; + +/// +/// 网络 IP 端点管理器实现 +/// +public class NetworkIPEndPointManager : INetworkIPEndPointManager +{ + private readonly ILogger _logger; + private readonly object _lock = new(); + private RanIPEndPoint _ranEndPoint; + private readonly List _cnEndPoints = new(); + private readonly List _imsEndPoints = new(); + + public NetworkIPEndPointManager(ILogger logger) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + /// 更新 IP 端点信息 + /// + /// IP 端点信息集合 + public void UpdateEndPoints(NetworkIPEndPoints endPoints) + { + if (endPoints == null) + { + _logger.LogWarning("更新 IP 端点信息失败:端点信息集合为 null"); + return; + } + + lock (_lock) + { + // 更新 RAN 端点 + _ranEndPoint = endPoints.RanEndPoint; + if (_ranEndPoint == null) + { + _logger.LogInformation("RAN 端点信息为空"); + } + + // 更新 CN 端点列表 + _cnEndPoints.Clear(); + if (endPoints.CnEndPoints != null && endPoints.CnEndPoints.Any()) + { + _cnEndPoints.AddRange(endPoints.CnEndPoints); + _logger.LogInformation("更新 CN 端点列表,共 {Count} 个端点", endPoints.CnEndPoints.Count); + } + else + { + _logger.LogInformation("CN 端点列表为空"); + } + + // 更新 IMS 端点列表 + _imsEndPoints.Clear(); + if (endPoints.ImsEndPoints != null && endPoints.ImsEndPoints.Any()) + { + _imsEndPoints.AddRange(endPoints.ImsEndPoints); + _logger.LogInformation("更新 IMS 端点列表,共 {Count} 个端点", endPoints.ImsEndPoints.Count); + } + else + { + _logger.LogInformation("IMS 端点列表为空"); + } + } + } + + /// + /// 获取 RAN 端点信息 + /// + public RanIPEndPoint GetRanEndPoint() + { + lock (_lock) + { + return _ranEndPoint; + } + } + + /// + /// 获取 CN 端点列表 + /// + public List GetCnEndPoints() + { + lock (_lock) + { + return new List(_cnEndPoints); + } + } + + /// + /// 获取 IMS 端点列表 + /// + public List GetImsEndPoints() + { + lock (_lock) + { + return new List(_imsEndPoints); + } + } + + /// + /// 清除所有端点信息 + /// + public void Clear() + { + lock (_lock) + { + _ranEndPoint = null; + _cnEndPoints.Clear(); + _imsEndPoints.Clear(); + _logger.LogInformation("已清除所有 IP 端点信息"); + } + } +} \ No newline at end of file