From f8a2f31a58c253d928ce1cea8e4b51f1efae798d Mon Sep 17 00:00:00 2001
From: root <295172551@qq.com>
Date: Thu, 31 Jul 2025 00:53:28 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DNetworkConfigCopier=E6=96=B9?=
=?UTF-8?q?=E6=B3=95=E8=BF=94=E5=9B=9E=E7=B1=BB=E5=9E=8B=EF=BC=8C=E6=94=B9?=
=?UTF-8?q?=E4=B8=BA=E5=85=83=E7=BB=84=E8=BF=94=E5=9B=9E=E6=A8=A1=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修改CreateCellularNetworkConfigurationFile返回类型为元组
- 修改CreateCoreNetworkImsConfigurationFiles返回类型为元组
- 更新接口定义和调用代码
- 简化错误处理,提高代码可读性
- 更新modify.md记录修改内容
---
CoreAgent.Domain/CoreAgent.Domain.csproj | 4 -
.../Entities/NetworkConfiguration.cs | 29 +-
.../Network/IGeneralCellularNetworkService.cs | 25 +
.../Network/INetworkConfigCopier.cs | 17 +-
.../Network/CellularNetworkConfiguration.cs | 60 ++
.../Network/CellularNetworkService.cs | 2 +-
.../Network/GeneralCellularNetworkService.cs | 512 +++++++++++++++
.../Services/Network/NetworkConfigCopier.cs | 339 +++++++++-
modify.md | 615 ++++++++++++------
9 files changed, 1394 insertions(+), 209 deletions(-)
create mode 100644 CoreAgent.Domain/Interfaces/Network/IGeneralCellularNetworkService.cs
create mode 100644 CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
create mode 100644 CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
diff --git a/CoreAgent.Domain/CoreAgent.Domain.csproj b/CoreAgent.Domain/CoreAgent.Domain.csproj
index f32cd8c..5d64e9c 100644
--- a/CoreAgent.Domain/CoreAgent.Domain.csproj
+++ b/CoreAgent.Domain/CoreAgent.Domain.csproj
@@ -20,8 +20,4 @@
-
-
-
-
diff --git a/CoreAgent.Domain/Entities/NetworkConfiguration.cs b/CoreAgent.Domain/Entities/NetworkConfiguration.cs
index 59c4ad7..fb67f50 100644
--- a/CoreAgent.Domain/Entities/NetworkConfiguration.cs
+++ b/CoreAgent.Domain/Entities/NetworkConfiguration.cs
@@ -31,18 +31,9 @@ namespace CoreAgent.Domain.Entities
[JsonPropertyName("coreOrImsConfigs")]
public List CoreOrImsConfigs { get; set; }
- ///
- /// APN配置
- ///
- [Required(ErrorMessage = "APN配置不能为空")]
[JsonPropertyName("apn")]
public string Apn { get; set; }
- ///
- /// 频段配置
- ///
- [Required(ErrorMessage = "频段配置不能为空")]
- [MinLength(1, ErrorMessage = "至少需要一个频段配置")]
[JsonPropertyName("band")]
public List Band { get; set; }
@@ -69,8 +60,8 @@ namespace CoreAgent.Domain.Entities
string configKey,
string ragConfig,
List coreOrImsConfigs,
- string apn,
- List band,
+ string apn=null,
+ List band=null,
string comment = null)
{
var config = new NetworkConfiguration
@@ -118,13 +109,13 @@ namespace CoreAgent.Domain.Entities
}
// 验证频段格式
- foreach (var band in Band)
- {
- if ((!band.StartsWith("B") && !band.StartsWith("N")) || !int.TryParse(band.Substring(1), out _))
- {
- yield return new ValidationResult($"频段格式不正确: {band},应为 B1、B2 或者 N78 等格式");
- }
- }
+ //foreach (var band in Band)
+ //{
+ // if ((!band.StartsWith("B") && !band.StartsWith("N")) || !int.TryParse(band.Substring(1), out _))
+ // {
+ // yield return new ValidationResult($"频段格式不正确: {band},应为 B1、B2 或者 N78 等格式");
+ // }
+ //}
}
///
@@ -181,7 +172,6 @@ namespace CoreAgent.Domain.Entities
/// 核心网配置文件路径
///
[Required(ErrorMessage = "核心网配置路径不能为空")]
- //[RegularExpression(@"^Config/CoreNetwork/.*\.cfg$", ErrorMessage = "核心网配置路径格式不正确")]
[JsonPropertyName("coreNetworkConfig")]
public string CoreNetworkConfig { get; set; }
@@ -189,7 +179,6 @@ namespace CoreAgent.Domain.Entities
/// IMS配置文件路径
///
[Required(ErrorMessage = "IMS配置路径不能为空")]
- //[RegularExpression(@"^Config/Ims/.*\.cfg$", ErrorMessage = "IMS配置路径格式不正确")]
[JsonPropertyName("imsConfig")]
public string ImsConfig { get; set; }
}
diff --git a/CoreAgent.Domain/Interfaces/Network/IGeneralCellularNetworkService.cs b/CoreAgent.Domain/Interfaces/Network/IGeneralCellularNetworkService.cs
new file mode 100644
index 0000000..e3d651e
--- /dev/null
+++ b/CoreAgent.Domain/Interfaces/Network/IGeneralCellularNetworkService.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using CoreAgent.Domain.Models.Network;
+
+namespace CoreAgent.Domain.Interfaces.Network
+{
+ public interface IGeneralCellularNetworkService
+ {
+ ///
+ /// 启动蜂窝网络
+ ///
+ /// 网络配置映射Key
+ /// 启动结果
+ Task StartAsync(CellularNetworkConfiguration cellular);
+
+ ///
+ /// 停止蜂窝网络
+ ///
+ /// 停止结果
+ Task StopAsync(string RuntimeCode);
+ }
+}
diff --git a/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs b/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
index 8e79e70..66dc306 100644
--- a/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
+++ b/CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
@@ -9,13 +9,28 @@ namespace CoreAgent.Domain.Interfaces.Network;
///
public interface INetworkConfigCopier
{
+ ///
+ /// 创建蜂窝网络配置文件
+ ///
+ /// 蜂窝网络配置
+ /// 应用设置
+ /// (IsSuccess: 是否成功, ErrorMessage: 错误信息, NetworkConfiguration: 网络配置对象)
+ Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)> CreateCellularNetworkConfigurationFile(CellularNetworkConfiguration cellular, AppSettings appSettings);
+
+ ///
+ /// 删除蜂窝网络配置文件
+ ///
+ /// 网络配置
+ /// 删除结果
+ NetworkConfigCopyResult DeleteCellularNetworkConfigurationFile(NetworkConfiguration configuration);
+
///
/// 将配置值复制到临时目录并更新配置路径
///
/// 网络配置
/// 应用设置
/// 复制结果
- Task CopyConfigValuesToTempAsync(NetworkConfiguration networkConfig, AppSettings appSettings);
+ NetworkConfigCopyResult CopyConfigValuesToTempAsync(NetworkConfiguration networkConfig, AppSettings appSettings);
///
/// 获取所有配置文件的 IP 端点信息
diff --git a/CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs b/CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
new file mode 100644
index 0000000..e59bdac
--- /dev/null
+++ b/CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
@@ -0,0 +1,60 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace CoreAgent.Domain.Models.Network;
+
+///
+/// 蜂窝网络配置实体
+///
+public class CellularNetworkConfiguration
+{
+ ///
+ /// 设备代码
+ ///
+ [Required(ErrorMessage = "设备代码不能为空")]
+ public string DeviceCode { get; set; }
+
+ ///
+ /// 运行时代码
+ ///
+ [Required(ErrorMessage = "运行时代码不能为空")]
+ public string RuntimeCode { get; set; }
+
+ ///
+ /// 无线接入网配置
+ ///
+ public string RadioAccessNetworkConfiguration { get; set; }
+
+ ///
+ /// 核心网IMS配置集合
+ ///
+ public List CoreNetworkImsConfigurations { get; set; } = new List();
+
+}
+
+///
+/// 核心网IMS配置对象
+///
+public class CoreNetworkImsConfiguration
+{
+ ///
+ /// 索引
+ ///
+ public int Index { get; set; }
+
+ ///
+ /// PLMN标识
+ ///
+ [Required(ErrorMessage = "PLMN标识不能为空")]
+ public string Plmn { get; set; }
+
+ ///
+ /// 核心网配置
+ ///
+ public string CoreNetworkConfiguration { get; set; }
+
+ ///
+ /// IMS服务配置
+ ///
+ public string ImsServiceConfiguration { get; set; }
+
+}
\ No newline at end of file
diff --git a/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs b/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
index cd2ee51..ac43610 100644
--- a/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
+++ b/CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
@@ -307,7 +307,7 @@ public class CellularNetworkService : ICellularNetworkService
var step3Start = DateTime.UtcNow;
_logger.LogDebug("步骤3开始:复制配置值到临时目录");
- var copyResult = await _configCopier.CopyConfigValuesToTempAsync(config, _context.GetAppSettings());
+ var copyResult = _configCopier.CopyConfigValuesToTempAsync(config, _context.GetAppSettings());
if (!copyResult.IsSuccess)
{
var message = $"复制配置值到临时目录失败: {copyResult.ErrorMessage}";
diff --git a/CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs b/CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
new file mode 100644
index 0000000..252662d
--- /dev/null
+++ b/CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
@@ -0,0 +1,512 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using CoreAgent.Domain.Entities;
+using CoreAgent.Domain.Interfaces.Network;
+using CoreAgent.Domain.Interfaces.System.Command;
+using CoreAgent.Domain.Interfaces;
+using CoreAgent.Domain.Models.Network;
+using CoreAgent.ProtocolClient.Interfaces;
+using CoreAgent.ProtocolClient.ProtocolEngineCore;
+using CoreAgent.WebSocketTransport.Interfaces;
+using Microsoft.Extensions.Logging;
+
+namespace CoreAgent.Infrastructure.Services.Network
+{
+ ///
+ /// 蜂窝网络服务实现
+ ///
+ public class GeneralCellularNetworkService : IGeneralCellularNetworkService
+ {
+ private readonly ILogger _logger;
+ private readonly ILoggerFactory _loggerFactory;
+ private readonly ISystemCommandExecutor _commandExecutor;
+ private readonly INetworkConfigurationService _configService;
+ private readonly ICellularNetworkContext _context;
+ private readonly INetworkConfigCopier _configCopier;
+ private readonly INetworkInterfaceManager _interfaceManager;
+ private readonly INetworkStatusMonitor _statusMonitor;
+ private readonly IWebSocketTransport _webSocketTransport;
+ private readonly IProtocolLogObserver _protocolLogObserver;
+ private readonly IProtocolWsClientManager _protocolWsClientManager;
+ private static readonly SemaphoreSlim _startLock = new(1, 1);
+ private const int LockTimeoutSeconds = 60;
+
+
+ public GeneralCellularNetworkService(
+ ILogger logger,
+ ILoggerFactory loggerFactory,
+ ISystemCommandExecutor commandExecutor,
+ INetworkConfigurationService configService,
+ ICellularNetworkContext context,
+ INetworkConfigCopier configCopier,
+ INetworkInterfaceManager interfaceManager,
+ INetworkStatusMonitor statusMonitor,
+ IWebSocketTransport webSocketTransport,
+ IProtocolLogObserver protocolLogObserver,
+ IProtocolWsClientManager protocolWsClientManager)
+ {
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
+ _commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor));
+ _configService = configService ?? throw new ArgumentNullException(nameof(configService));
+ _context = context ?? throw new ArgumentNullException(nameof(context));
+ _configCopier = configCopier ?? throw new ArgumentNullException(nameof(configCopier));
+ _interfaceManager = interfaceManager ?? throw new ArgumentNullException(nameof(interfaceManager));
+ _statusMonitor = statusMonitor;
+ _webSocketTransport = webSocketTransport ?? throw new ArgumentNullException(nameof(webSocketTransport));
+ _protocolLogObserver = protocolLogObserver ?? throw new ArgumentNullException(nameof(protocolLogObserver));
+ _protocolWsClientManager = protocolWsClientManager ?? throw new ArgumentNullException(nameof(protocolWsClientManager));
+ }
+
+ ///
+ /// 启动蜂窝网络
+ ///
+ /// 网络配置键
+ /// 启动结果
+ public async Task StartAsync(CellularNetworkConfiguration cellular)
+ {
+ string key = cellular.RuntimeCode;
+ // 1. 参数验证
+ if (string.IsNullOrEmpty(key))
+ {
+ _logger.LogError("启动蜂窝网络失败:配置键为空");
+ return CellularNetworkOperationResult.Failure("启动蜂窝网络失败:配置键为空");
+ }
+
+ try
+ {
+ // 2. 获取启动锁,防止并发启动
+ if (!await _startLock.WaitAsync(TimeSpan.FromSeconds(LockTimeoutSeconds)))
+ {
+ _logger.LogWarning("蜂窝网络启动操作被锁定,可能已有其他启动操作正在进行");
+ return CellularNetworkOperationResult.Failure("蜂窝网络启动操作被锁定,可能已有其他启动操作正在进行");
+ }
+
+ // 3. 状态检查
+ // 如果是第二次启动(已初始化),需要先检查网络状态
+ if (_context.IsInitialized)
+ {
+ // 检查网络状态,确保没有冲突的配置
+ var stateCheckResult = CheckNetworkState(key);
+ if (!stateCheckResult.IsSuccess)
+ {
+ return stateCheckResult;
+ }
+ }
+
+ // 4. 初始化网络上下文
+ _context.Initialize(key);
+
+ // 5. 启动网络
+ var result = await StartNetworkAsync(cellular);
+ if (!result.IsSuccess)
+ {
+ _logger.LogWarning("启动蜂窝网络内部操作失败,重置上下文");
+ _context.Reset();
+ return result;
+ }
+
+ return result;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "启动蜂窝网络失败");
+ // 重置上下文
+ _context.Reset();
+ return CellularNetworkOperationResult.Failure($"启动蜂窝网络失败: {ex.Message}");
+ }
+ finally
+ {
+ _startLock.Release();
+ }
+ }
+
+ ///
+ /// 停止蜂窝网络
+ ///
+ /// 网络配置键
+ /// 停止操作的结果
+ public async Task StopAsync(string key)
+ {
+ string neConfigKey = _context.GetNeConfigKey();
+ try
+ {
+ // 检查是否是相同的配置
+ if (key != neConfigKey)
+ {
+ var message = $"停止操作失败:当前运行配置 {neConfigKey} 与请求停止的配置 {key} 不匹配";
+ _logger.LogWarning(message);
+ return CellularNetworkOperationResult.Failure(message);
+ }
+
+ // 1. 检查当前网络状态
+ var state = _context.GetNetworkState();
+ if (state.CurrentStatus == NetworkStatus.Disconnected || state.CurrentStatus == NetworkStatus.Unknown)
+ {
+ _logger.LogWarning("蜂窝网络已经处于断开或未知状态,无需停止");
+ _context.Reset(); // 重置上下文状态
+ return CellularNetworkOperationResult.Success(NetworkStatus.Disconnected);
+ }
+
+ // 2. 检查 RAN 退出状态(仅当配置类型为 BothRagAndCore 或 RagOnly 时)
+ if (_context.CurrentConfigType is NetworkConfigType.BothRagAndCore or NetworkConfigType.RagOnly)
+ {
+ var isRanQuit = await _statusMonitor.CheckRanQuitAsync(_context.NetworkIPEndPointManager.GetRanEndPoint());
+ if (!isRanQuit)
+ {
+ _logger.LogWarning("RAN 退出状态检查失败");
+ return CellularNetworkOperationResult.Failure("RAN 退出状态检查失败");
+ }
+ }
+
+ // 3. 执行网络接口初始化命令
+ var initResult = await _interfaceManager.ExecuteInitializeCommandsAsync();
+ if (!initResult.IsSuccess)
+ {
+ _logger.LogWarning("执行初始化命令失败: {ErrorMessage}", initResult.ErrorMessage);
+ }
+
+ // 4. 禁用网络配置
+ var disableResult = await _interfaceManager.DisableAsync(neConfigKey);
+ if (!disableResult.IsSuccess)
+ {
+ return CellularNetworkOperationResult.Failure(disableResult.ErrorMessage);
+ }
+
+ // 5. 停止所有协议客户端
+ try
+ {
+ _logger.LogInformation("开始停止所有协议客户端");
+ _protocolWsClientManager.StopAllClients();
+ _logger.LogInformation("所有协议客户端停止完成");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "停止协议客户端失败");
+ // 不返回失败,继续执行后续步骤
+ }
+
+ // 6. 停止 WebSocket 传输连接
+ var webSocketConnected = await StopWebSocketTransportAsync();
+ if (!webSocketConnected)
+ {
+ _logger.LogError("WebSocket 传输连接停止失败,服务端可能未启动");
+ return CellularNetworkOperationResult.Failure("WebSocket 传输连接停止失败");
+ }
+ _logger.LogInformation("WebSocket 传输连接停止成功");
+ // 7. 收集所有网络端点信息
+ var endPoints = new NetworkIPEndPointCollection
+ {
+ RanEndPoint = _context.NetworkIPEndPointManager.GetRanEndPoint(),
+ ImsEndPoints = _context.NetworkIPEndPointManager.GetImsEndPoints(),
+ CnEndPoints = _context.NetworkIPEndPointManager.GetCnEndPoints()
+ };
+
+ // 8. 检查网络端点连接状态
+ _logger.LogInformation("开始检查所有网络端点的连接状态");
+ var statusCheckResult = await _statusMonitor.CheckAllEndPointsStatusAsync(endPoints, _context.CurrentConfigType, isStartOperation: false);
+ if (!statusCheckResult.IsSuccess)
+ {
+ _logger.LogWarning("网络端点仍然处于连接状态,停止操作失败");
+ return CellularNetworkOperationResult.Failure("网络端点仍然处于连接状态,停止操作失败");
+ }
+
+ // 9. 重置上下文并返回成功结果
+ _context.Reset();
+ return CellularNetworkOperationResult.Success(NetworkStatus.Disconnected);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "停止蜂窝网络配置 {ConfigKey} 失败", neConfigKey);
+ return CellularNetworkOperationResult.Failure($"停止蜂窝网络失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 检查网络状态
+ ///
+ /// 新的网络配置键
+ /// 检查结果
+ private CellularNetworkOperationResult CheckNetworkState(string newConfigKey)
+ {
+ try
+ {
+ // 获取当前网络状态
+ var currentKey = _context.GetNeConfigKey();
+ var currentState = _context.GetNetworkState();
+
+ // 检查是否已初始化
+ if (!string.IsNullOrEmpty(currentKey))
+ {
+ // 检查是否是相同的配置
+ if (currentKey == newConfigKey)
+ {
+ // 检查当前状态
+ if (currentState.CurrentStatus == NetworkStatus.Connected)
+ {
+ return CellularNetworkOperationResult.Failure("当前网络配置已经处于连接状态");
+ }
+ }
+ else
+ {
+ // 检查当前网络状态
+ if (currentState.CurrentStatus == NetworkStatus.Connected)
+ {
+ var message = $"检测到不同的网络配置,当前运行配置: {currentKey},新配置: {newConfigKey},请先停止当前网络";
+ _logger.LogWarning(message);
+ return CellularNetworkOperationResult.Failure(message);
+ }
+ }
+ }
+
+ return CellularNetworkOperationResult.Success(NetworkStatus.Unknown);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "检查网络状态失败");
+ return CellularNetworkOperationResult.Failure($"检查网络状态失败: {ex.Message}");
+ }
+ }
+
+ private async Task StartNetworkAsync(CellularNetworkConfiguration cellular)
+ {
+ string key =cellular.RuntimeCode;
+ var startTime = DateTime.UtcNow;
+ _logger.LogInformation("开始启动网络配置 {ConfigKey},开始时间: {StartTime}", key, startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"));
+
+ // 1. 获取并验证网络配置
+ var step1Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤1开始:获取并验证网络配置");
+
+ var (isSuccess, errorMsg, config) = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings());
+ if (!isSuccess)
+ {
+ var message = $"创建网络配置文件失败: {errorMsg}";
+ _logger.LogError(message);
+ return CellularNetworkOperationResult.Failure(message);
+ }
+
+ var step1Duration = (DateTime.UtcNow - step1Start).TotalMilliseconds;
+ _logger.LogDebug("步骤1完成:获取并验证网络配置,耗时: {Duration}ms", step1Duration.ToString("F2"));
+
+ // 2. 执行网络接口初始化命令
+ var step2Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤2开始:执行网络接口初始化命令");
+
+ var initResult = await _interfaceManager.ExecuteInitializeCommandsAsync(true);
+ if (!initResult.IsSuccess)
+ {
+ _logger.LogWarning("执行初始化命令失败: {ErrorMessage}", initResult.ErrorMessage);
+ }
+
+ var step2Duration = (DateTime.UtcNow - step2Start).TotalMilliseconds;
+ _logger.LogDebug("步骤2完成:执行网络接口初始化命令,耗时: {Duration}ms", step2Duration.ToString("F2"));
+
+ // 3. 复制配置值到临时目录
+ var step3Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤3开始:复制配置值到临时目录");
+
+ var copyResult = _configCopier.CopyConfigValuesToTempAsync(config, _context.GetAppSettings());
+ if (!copyResult.IsSuccess)
+ {
+ var message = $"复制配置值到临时目录失败: {copyResult.ErrorMessage}";
+ _logger.LogError(message);
+ return CellularNetworkOperationResult.Failure(message);
+ }
+
+ var step3Duration = (DateTime.UtcNow - step3Start).TotalMilliseconds;
+ _logger.LogDebug("步骤3完成:复制配置值到临时目录,耗时: {Duration}ms", step3Duration.ToString("F2"));
+
+ // 4. 获取并验证 IP 端点信息
+ var step4Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤4开始:获取并验证 IP 端点信息");
+
+ var (endPoints, hasAnyEndPoint) = await _configCopier.GetComAddrInfoAsync(config);
+ if (!hasAnyEndPoint)
+ {
+ var message = "未获取到任何有效的 IP 端点信息";
+ _logger.LogError(message);
+ return CellularNetworkOperationResult.Failure(message);
+ }
+
+ var step4Duration = (DateTime.UtcNow - step4Start).TotalMilliseconds;
+ _logger.LogDebug("步骤4完成:获取并验证 IP 端点信息,耗时: {Duration}ms", step4Duration.ToString("F2"));
+
+ // 5. 更新 IP 端点管理器
+ var step5Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤5开始:更新 IP 端点管理器");
+
+ _context.NetworkIPEndPointManager.UpdateEndPoints(endPoints);
+
+ var step5Duration = (DateTime.UtcNow - step5Start).TotalMilliseconds;
+ _logger.LogDebug("步骤5完成:更新 IP 端点管理器,耗时: {Duration}ms", step5Duration.ToString("F2"));
+
+ // 6. 创建协议客户端配置
+ var step6Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤6开始:创建协议客户端配置");
+
+ var protocolConfigFactory = new ProtocolClientConfigFactory(_loggerFactory.CreateLogger(), _context);
+ var configCreated = protocolConfigFactory.CreateFromEntities();
+ if (configCreated)
+ {
+ _logger.LogInformation("协议客户端配置创建成功,共创建 {ConfigCount} 个配置", protocolConfigFactory.ConfigCount);
+ }
+ else
+ {
+ _logger.LogWarning("协议客户端配置创建失败");
+ return CellularNetworkOperationResult.Failure("协议客户端配置创建失败");
+ }
+
+ var step6Duration = (DateTime.UtcNow - step6Start).TotalMilliseconds;
+ _logger.LogDebug("步骤6完成:创建协议客户端配置,耗时: {Duration}ms", step6Duration.ToString("F2"));
+
+ // 7. 启动 WebSocket 传输连接
+ var step7Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤7开始:启动 WebSocket 传输连接");
+
+ var webSocketConnected = await StartWebSocketTransportAsync();
+ if (!webSocketConnected)
+ {
+ _logger.LogError("WebSocket 传输连接启动失败,服务端可能未启动");
+ return CellularNetworkOperationResult.Failure("WebSocket 传输连接启动失败,服务端可能未启动");
+ }
+ _logger.LogInformation("WebSocket 传输连接启动成功");
+
+ var step7Duration = (DateTime.UtcNow - step7Start).TotalMilliseconds;
+ _logger.LogDebug("步骤7完成:启动 WebSocket 传输连接,耗时: {Duration}ms", step7Duration.ToString("F2"));
+
+ // 8. 启动网络配置
+ var step8Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤8开始:启动网络配置");
+ _logger.LogInformation("正在启动蜂窝网络配置: {ConfigKey}", key);
+
+ var enableResult = await _interfaceManager.EnableAsync(config);
+ if (!enableResult.IsSuccess)
+ {
+ var message = $"启动网络配置失败: {enableResult.ErrorMessage}";
+ _logger.LogError(message);
+ return CellularNetworkOperationResult.Failure(message);
+ }
+
+ var step8Duration = (DateTime.UtcNow - step8Start).TotalMilliseconds;
+ _logger.LogDebug("步骤8完成:启动网络配置,耗时: {Duration}ms", step8Duration.ToString("F2"));
+
+ // 9. 更新网络配置类型
+ var step9Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤9开始:更新网络配置类型");
+
+ _context.UpdateNetworkConfigType(enableResult.ConfigType);
+ _logger.LogInformation("更新网络配置类型: {ConfigType}", enableResult.ConfigType);
+
+ var step9Duration = (DateTime.UtcNow - step9Start).TotalMilliseconds;
+ _logger.LogDebug("步骤9完成:更新网络配置类型,耗时: {Duration}ms", step9Duration.ToString("F2"));
+
+ // 10. 检查网络端点连接状态
+ var step10Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤10开始:检查网络端点连接状态");
+ _logger.LogInformation("开始检查所有网络端点的连接状态");
+
+ var statusCheckResult = await _statusMonitor.CheckAllEndPointsStatusAsync(endPoints, enableResult.ConfigType, isStartOperation: true);
+ if (!statusCheckResult.IsSuccess)
+ {
+ var errorMessage = string.Join("; ", statusCheckResult.ErrorMessage);
+ _logger.LogWarning("网络端点状态检查未通过: {ErrorMessage}", errorMessage);
+ return CellularNetworkOperationResult.Failure($"网络端点状态检查失败: {errorMessage}");
+ }
+ _logger.LogInformation("网络端点状态检查完成,所有端点状态正常");
+
+ var step10Duration = (DateTime.UtcNow - step10Start).TotalMilliseconds;
+ _logger.LogDebug("步骤10完成:检查网络端点连接状态,耗时: {Duration}ms", step10Duration.ToString("F2"));
+
+ // 11. 更新网络状态
+ var step11Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤11开始:更新网络状态");
+
+ var state = _context.GetNetworkState();
+ state.MarkAsStarted();
+
+ var step11Duration = (DateTime.UtcNow - step11Start).TotalMilliseconds;
+ _logger.LogDebug("步骤11完成:更新网络状态,耗时: {Duration}ms", step11Duration.ToString("F2"));
+
+ // 12. 启动所有协议客户端
+ var step12Start = DateTime.UtcNow;
+ _logger.LogDebug("步骤12开始:启动所有协议客户端");
+
+ try
+ {
+ var protocolConfigs = protocolConfigFactory.GetAllConfigs();
+ _protocolWsClientManager.StartAllClients(protocolConfigs);
+ _logger.LogInformation("所有协议客户端启动完成");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "启动协议客户端失败");
+ return CellularNetworkOperationResult.Failure($"启动协议客户端失败: {ex.Message}");
+ }
+
+ var step12Duration = (DateTime.UtcNow - step12Start).TotalMilliseconds;
+ _logger.LogDebug("步骤12完成:启动所有协议客户端,耗时: {Duration}ms", step12Duration.ToString("F2"));
+
+ var endTime = DateTime.UtcNow;
+ var duration = endTime - startTime;
+ _logger.LogInformation("蜂窝网络配置 {ConfigKey} 启动成功,当前状态: {Status},总耗时: {Duration}ms",
+ key, state.CurrentStatus, duration.TotalMilliseconds.ToString("F2"));
+
+ // 删除临时配置文件
+ var deleteResult = _configCopier.DeleteCellularNetworkConfigurationFile(config);
+ if (!deleteResult.IsSuccess)
+ {
+ _logger.LogWarning("删除临时配置文件失败: {ErrorMessage}", deleteResult.ErrorMessage);
+ // 不返回失败,因为网络已经启动成功
+ }
+ else
+ {
+ _logger.LogInformation("临时配置文件删除成功");
+ }
+
+ return CellularNetworkOperationResult.Success(state.CurrentStatus);
+ }
+
+ ///
+ /// 启动 WebSocket 传输连接
+ ///
+ /// 连接是否成功
+ private async Task StartWebSocketTransportAsync()
+ {
+ try
+ {
+ _logger.LogInformation("开始启动 WebSocket 传输连接");
+ await _webSocketTransport.ConnectAsync();
+ return _webSocketTransport.IsConnected;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "WebSocket 传输连接启动失败");
+ return false;
+ }
+ }
+
+
+ ///
+ /// 停止 WebSocket 传输连接
+ ///
+ /// 停止是否成功
+ private async Task StopWebSocketTransportAsync()
+ {
+ try
+ {
+ _logger.LogInformation("开始停止 WebSocket 传输连接");
+ await _webSocketTransport.CloseAsync();
+ return !_webSocketTransport.IsConnected;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "WebSocket 传输连接停止失败");
+ return false;
+ }
+ }
+ }
+}
diff --git a/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs b/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
index ac10f3c..e27d43d 100644
--- a/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
+++ b/CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
@@ -1,9 +1,11 @@
+using System.Collections.Generic;
using CoreAgent.Domain.Entities;
using CoreAgent.Domain.Interfaces;
using CoreAgent.Domain.Interfaces.Network;
using CoreAgent.Domain.Interfaces.System.Command;
using CoreAgent.Domain.Models.Network;
using CoreAgent.Domain.Models.System;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace CoreAgent.Infrastructure.Services.Network;
@@ -25,11 +27,345 @@ public class NetworkConfigCopier : INetworkConfigCopier
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor));
}
+ public async Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)> CreateCellularNetworkConfigurationFile(CellularNetworkConfiguration cellular, AppSettings appSettings)
+ {
+ _logger.LogInformation("开始创建蜂窝网络配置文件,RuntimeCode: {RuntimeCode}", cellular?.RuntimeCode);
+
+ try
+ {
+ // 参数验证
+ if (cellular == null)
+ {
+ _logger.LogError("CellularNetworkConfiguration 参数为空");
+ return (false, "CellularNetworkConfiguration 参数为空", null);
+ }
+
+ if (appSettings == null)
+ {
+ _logger.LogError("AppSettings 参数为空");
+ return (false, "AppSettings 参数为空", null);
+ }
+
+ if (string.IsNullOrWhiteSpace(cellular.RuntimeCode))
+ {
+ _logger.LogError("RuntimeCode 为空");
+ return (false, "RuntimeCode 不能为空", null);
+ }
+
+ // 确保目录存在
+ EnsureDirectoriesExist(appSettings);
+
+ string ranConfigPath = Path.Combine(appSettings.RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg");
+ _logger.LogInformation("RAN配置文件路径: {RanConfigPath}", ranConfigPath);
+
+ List list = new List();
+
+ // 创建RAN配置文件
+ if (!string.IsNullOrWhiteSpace(cellular.RadioAccessNetworkConfiguration))
+ {
+ _logger.LogInformation("开始创建RAN配置文件");
+ var ranResult = await CreateRadioAccessNetworkConfigurationFile(ranConfigPath, cellular.RadioAccessNetworkConfiguration);
+ if (!ranResult.IsSuccess)
+ {
+ return (false, $"创建RAN配置文件失败: {ranResult.ErrorMessage}", null);
+ }
+ _logger.LogInformation("RAN配置文件创建成功: {RanConfigPath}", ranConfigPath);
+ }
+ else
+ {
+ _logger.LogWarning("RadioAccessNetworkConfiguration 为空,跳过RAN配置文件创建");
+ }
+
+ // 创建核心网络和IMS配置文件
+ if (cellular.CoreNetworkImsConfigurations != null && cellular.CoreNetworkImsConfigurations.Count > 0)
+ {
+ _logger.LogInformation("开始创建核心网络和IMS配置文件,配置数量: {Count}", cellular.CoreNetworkImsConfigurations.Count);
+ var (coreImsSuccess, coreImsError, coreImsConfigs) = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings);
+ if (!coreImsSuccess)
+ {
+ return (false, $"创建核心网络和IMS配置文件失败: {coreImsError}", null);
+ }
+ list = coreImsConfigs;
+ _logger.LogInformation("核心网络和IMS配置文件创建完成,成功创建: {Count} 个配置", list.Count);
+ }
+ else
+ {
+ _logger.LogWarning("CoreNetworkImsConfigurations 为空或数量为0,跳过核心网络和IMS配置文件创建");
+ }
+
+ NetworkConfiguration network = NetworkConfiguration.Create(cellular.RuntimeCode, ranConfigPath, list);
+ _logger.LogInformation("蜂窝网络配置文件创建完成,RuntimeCode: {RuntimeCode}", cellular.RuntimeCode);
+ return (true, null, network);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "创建蜂窝网络配置文件时发生错误,RuntimeCode: {RuntimeCode}", cellular?.RuntimeCode);
+ return (false, $"创建蜂窝网络配置文件时发生错误: {ex.Message}", null);
+ }
+ }
+
+ public async Task CreateRadioAccessNetworkConfigurationFile(string ranConfigPath, string radioAccessNetworkConfiguration)
+ {
+ _logger.LogInformation("开始创建RAN配置文件: {RanConfigPath}", ranConfigPath);
+
+ try
+ {
+ // 参数验证
+ if (string.IsNullOrWhiteSpace(ranConfigPath))
+ {
+ _logger.LogError("RAN配置文件路径为空");
+ return NetworkConfigCopyResult.Failure("RAN配置文件路径不能为空");
+ }
+
+ if (string.IsNullOrWhiteSpace(radioAccessNetworkConfiguration))
+ {
+ _logger.LogError("RAN配置内容为空");
+ return NetworkConfigCopyResult.Failure("RAN配置内容不能为空");
+ }
+
+ // 确保目录存在
+ var directory = Path.GetDirectoryName(ranConfigPath);
+ if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ _logger.LogInformation("创建目录: {Directory}", directory);
+ }
+
+ // 写入配置文件
+ await File.WriteAllTextAsync(ranConfigPath, radioAccessNetworkConfiguration);
+ _logger.LogInformation("RAN配置文件创建成功: {RanConfigPath}", ranConfigPath);
+ return NetworkConfigCopyResult.Success();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "创建RAN配置文件时发生错误: {RanConfigPath}", ranConfigPath);
+ return NetworkConfigCopyResult.Failure($"创建RAN配置文件时发生错误: {ex.Message}");
+ }
+ }
+
+ public async Task<(bool IsSuccess, string ErrorMessage, List CoreImsConfigs)> CreateCoreNetworkImsConfigurationFiles(string runtimeCode, List coreNetworkImsConfigurations, AppSettings appSettings)
+ {
+ _logger.LogInformation("开始创建核心网络和IMS配置文件,RuntimeCode: {RuntimeCode}, 配置数量: {Count}", runtimeCode, coreNetworkImsConfigurations?.Count ?? 0);
+
+ try
+ {
+ // 参数验证
+ if (string.IsNullOrWhiteSpace(runtimeCode))
+ {
+ _logger.LogError("RuntimeCode 为空");
+ return (false, "RuntimeCode 不能为空", null);
+ }
+
+ if (coreNetworkImsConfigurations == null || coreNetworkImsConfigurations.Count == 0)
+ {
+ _logger.LogWarning("CoreNetworkImsConfigurations 为空或数量为0");
+ return (true, null, new List());
+ }
+
+ if (appSettings == null)
+ {
+ _logger.LogError("AppSettings 参数为空");
+ return (false, "AppSettings 参数为空", null);
+ }
+
+ List list = new List();
+
+ foreach (var item in coreNetworkImsConfigurations)
+ {
+ try
+ {
+ _logger.LogInformation("处理配置项,Index: {Index}, Plmn: {Plmn}", item.Index, item.Plmn);
+
+ // 验证配置项
+ if (string.IsNullOrWhiteSpace(item.Plmn))
+ {
+ _logger.LogError("配置项PLMN为空,Index: {Index}", item.Index);
+ continue;
+ }
+
+ if (string.IsNullOrWhiteSpace(item.CoreNetworkConfiguration))
+ {
+ _logger.LogWarning("核心网络配置内容为空,Index: {Index}, Plmn: {Plmn}", item.Index, item.Plmn);
+ }
+
+ if (string.IsNullOrWhiteSpace(item.ImsServiceConfiguration))
+ {
+ _logger.LogWarning("IMS服务配置内容为空,Index: {Index}, Plmn: {Plmn}", item.Index, item.Plmn);
+ }
+
+ // 构建文件路径
+ string cnConfigPath = Path.Combine(appSettings.MmeConfigDirectory, "Cn", $"{runtimeCode}_{item.Plmn}.cfg");
+ string imsConfigPath = Path.Combine(appSettings.MmeConfigDirectory, "Ims", $"{runtimeCode}_{item.Plmn}.cfg");
+
+ _logger.LogInformation("CN配置文件路径: {CnConfigPath}", cnConfigPath);
+ _logger.LogInformation("IMS配置文件路径: {ImsConfigPath}", imsConfigPath);
+
+ // 确保目录存在
+ var cnDirectory = Path.GetDirectoryName(cnConfigPath);
+ var imsDirectory = Path.GetDirectoryName(imsConfigPath);
+
+ if (!string.IsNullOrEmpty(cnDirectory) && !Directory.Exists(cnDirectory))
+ {
+ Directory.CreateDirectory(cnDirectory);
+ _logger.LogInformation("创建CN目录: {Directory}", cnDirectory);
+ }
+
+ if (!string.IsNullOrEmpty(imsDirectory) && !Directory.Exists(imsDirectory))
+ {
+ Directory.CreateDirectory(imsDirectory);
+ _logger.LogInformation("创建IMS目录: {Directory}", imsDirectory);
+ }
+
+ // 写入配置文件
+ if (!string.IsNullOrWhiteSpace(item.CoreNetworkConfiguration))
+ {
+ await File.WriteAllTextAsync(cnConfigPath, item.CoreNetworkConfiguration);
+ _logger.LogInformation("CN配置文件创建成功: {CnConfigPath}", cnConfigPath);
+ }
+
+ if (!string.IsNullOrWhiteSpace(item.ImsServiceConfiguration))
+ {
+ await File.WriteAllTextAsync(imsConfigPath, item.ImsServiceConfiguration);
+ _logger.LogInformation("IMS配置文件创建成功: {ImsConfigPath}", imsConfigPath);
+ }
+
+ // 添加到结果列表
+ list.Add(new CoreImsConfig
+ {
+ Index = item.Index,
+ Plmn = item.Plmn,
+ CoreNetworkConfig = cnConfigPath,
+ ImsConfig = imsConfigPath
+ });
+
+ _logger.LogInformation("配置项处理完成,Index: {Index}, Plmn: {Plmn}", item.Index, item.Plmn);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "处理配置项时发生错误,Index: {Index}, Plmn: {Plmn}", item.Index, item.Plmn);
+ // 继续处理下一个配置项,不中断整个流程
+ }
+ }
+
+ _logger.LogInformation("核心网络和IMS配置文件创建完成,成功创建: {Count} 个配置", list.Count);
+ return (true, null, list);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "创建核心网络和IMS配置文件时发生错误,RuntimeCode: {RuntimeCode}", runtimeCode);
+ return (false, $"创建核心网络和IMS配置文件时发生错误: {ex.Message}", null);
+ }
+ }
+
+
+ public NetworkConfigCopyResult DeleteCellularNetworkConfigurationFile(NetworkConfiguration configuration)
+ {
+ _logger.LogInformation("开始删除蜂窝网络配置文件");
+
+ try
+ {
+ // 参数验证
+ if (configuration == null)
+ {
+ _logger.LogError("NetworkConfiguration 参数为空");
+ return NetworkConfigCopyResult.Failure("NetworkConfiguration 参数为空");
+ }
+
+ int deletedFilesCount = 0;
+
+ // 删除RAG配置文件
+ if (!string.IsNullOrWhiteSpace(configuration.RagConfig))
+ {
+ try
+ {
+ if (File.Exists(configuration.RagConfig))
+ {
+ File.Delete(configuration.RagConfig);
+ _logger.LogInformation("RAG配置文件删除成功: {RagConfig}", configuration.RagConfig);
+ deletedFilesCount++;
+ }
+ else
+ {
+ _logger.LogWarning("RAG配置文件不存在: {RagConfig}", configuration.RagConfig);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "删除RAG配置文件时发生错误: {RagConfig}", configuration.RagConfig);
+ // 继续处理其他文件,不中断整个流程
+ }
+ }
+ else
+ {
+ _logger.LogInformation("RAG配置文件路径为空,跳过删除");
+ }
+
+ // 删除核心网络和IMS配置文件
+ if (configuration.CoreOrImsConfigs != null && configuration.CoreOrImsConfigs.Count > 0)
+ {
+ _logger.LogInformation("开始删除核心网络和IMS配置文件,配置数量: {Count}", configuration.CoreOrImsConfigs.Count);
+
+ foreach (var item in configuration.CoreOrImsConfigs)
+ {
+ try
+ {
+ // 删除CN配置文件
+ if (!string.IsNullOrWhiteSpace(item.CoreNetworkConfig))
+ {
+ if (File.Exists(item.CoreNetworkConfig))
+ {
+ File.Delete(item.CoreNetworkConfig);
+ _logger.LogInformation("CN配置文件删除成功: {CoreNetworkConfig}", item.CoreNetworkConfig);
+ deletedFilesCount++;
+ }
+ else
+ {
+ _logger.LogWarning("CN配置文件不存在: {CoreNetworkConfig}", item.CoreNetworkConfig);
+ }
+ }
+
+ // 删除IMS配置文件
+ if (!string.IsNullOrWhiteSpace(item.ImsConfig))
+ {
+ if (File.Exists(item.ImsConfig))
+ {
+ File.Delete(item.ImsConfig);
+ _logger.LogInformation("IMS配置文件删除成功: {ImsConfig}", item.ImsConfig);
+ deletedFilesCount++;
+ }
+ else
+ {
+ _logger.LogWarning("IMS配置文件不存在: {ImsConfig}", item.ImsConfig);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "删除配置文件时发生错误,Index: {Index}, Plmn: {Plmn}", item.Index, item.Plmn);
+ // 继续处理下一个配置项,不中断整个流程
+ }
+ }
+ }
+ else
+ {
+ _logger.LogInformation("核心网络和IMS配置文件列表为空,跳过删除");
+ }
+
+ _logger.LogInformation("蜂窝网络配置文件删除完成,共删除 {DeletedFilesCount} 个文件", deletedFilesCount);
+ return NetworkConfigCopyResult.Success();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "删除蜂窝网络配置文件时发生错误");
+ return NetworkConfigCopyResult.Failure($"删除蜂窝网络配置文件时发生错误: {ex.Message}");
+ }
+ }
+
///
/// 将配置值复制到临时目录并更新配置路径
///
- public async Task CopyConfigValuesToTempAsync(NetworkConfiguration networkConfig, AppSettings appSettings)
+ public NetworkConfigCopyResult CopyConfigValuesToTempAsync(NetworkConfiguration networkConfig, AppSettings appSettings)
{
try
{
@@ -67,7 +403,6 @@ public class NetworkConfigCopier : INetworkConfigCopier
}
}
}
-
return NetworkConfigCopyResult.Success();
}
catch (Exception ex)
diff --git a/modify.md b/modify.md
index cc0801e..ad4cc87 100644
--- a/modify.md
+++ b/modify.md
@@ -2,108 +2,164 @@
## 2024年修改记录
-### 创建获取SN接口 - 遵循DDD设计架构
+### 创建蜂窝网络配置实体类
**修改时间**: 2024年
**修改文件**:
-- `CoreAgent.Domain/Models/System/DeviceInfo.cs` (新建)
-- `CoreAgent.Domain/Interfaces/System/IDeviceService.cs` (新建)
-- `CoreAgent.Infrastructure/Services/System/DeviceService.cs` (新建)
-- `CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs` (新建)
-- `CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs` (新建)
-- `CoreAgent.API/Controllers/SystemController.cs` (新建)
-- `CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs`
+- `CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs` (新建)
**修改内容**:
-1. **领域层设计**
- - 创建 `DeviceInfo` 模型,包含 `SerialNumber` 和 `Timestamp` 字段
- - 定义 `IDeviceService` 接口,提供获取SN的异步和同步方法
- - 遵循DDD设计原则,接口定义在领域层
-
-2. **基础设施层实现**
- - 实现 `DeviceService` 类,使用 `ISystemCommandExecutor` 执行系统命令
- - 支持Windows和Linux系统,自动选择对应的命令
- - Windows: `wmic bios get serialnumber /value`
- - Linux: `cat /sys/class/dmi/id/product_serial`
- - 提供完善的错误处理和日志记录
-
-3. **应用层设计**
- - 创建 `GetSerialNumberCommand` 命令类,返回 `ApiActionResult`
- - 实现 `GetSerialNumberCommandHandler` 处理器,返回包装后的结果
- - 使用MediatR模式处理命令
- - 在应用层统一处理成功和错误响应
-
-4. **API层设计**
- - 创建 `SystemController` 控制器,继承 `BaseApiController`
- - 提供 `GET /api/v1/system/serial-number` 接口
- - 直接返回应用层的 `ApiActionResult` 结果
- - 简化控制器逻辑,错误处理在应用层完成
-
-5. **依赖注入配置**
- - 在 `CommandServiceExtensions` 中注册 `IDeviceService`
- - 使用作用域生命周期管理
-
-6. **具体实现**:
+1. **创建CellularNetworkConfiguration实体类**
+ - 包含设备代码(DeviceCode)字符串属性
+ - 包含运行时代码(RuntimeCode)字符串属性
+ - 包含无线接入网配置(RadioAccessNetworkConfiguration)字符串属性
+ - 包含核心网IMS配置集合(List)属性
+
+2. **创建CoreNetworkImsConfiguration实体类**
+ - 包含索引(Index)整数属性
+ - 包含PLMN标识(Plmn)字符串属性
+ - 包含核心网配置(CoreNetworkConfiguration)字符串属性
+ - 包含IMS服务配置(ImsServiceConfiguration)字符串属性
+
+3. **具体实现**:
```csharp
- // 领域模型
- public class DeviceInfo
+ ///
+ /// 蜂窝网络配置实体
+ ///
+ public class CellularNetworkConfiguration
{
- public string SerialNumber { get; set; } = string.Empty;
- public DateTime Timestamp { get; set; } = DateTime.UtcNow;
+ ///
+ /// 设备代码
+ ///
+ public string DeviceCode { get; set; }
+
+ ///
+ /// 运行时代码
+ ///
+ public string RuntimeCode { get; set; }
+
+ ///
+ /// 无线接入网配置
+ ///
+ public string RadioAccessNetworkConfiguration { get; set; }
+
+ ///
+ /// 核心网IMS配置集合
+ ///
+ public List CoreNetworkImsConfigurations { get; set; } = new List();
}
- // 领域接口
- public interface IDeviceService
+ ///
+ /// 核心网IMS配置对象
+ ///
+ public class CoreNetworkImsConfiguration
{
- Task GetSerialNumberAsync();
- DeviceInfo GetSerialNumber();
+ ///
+ /// 索引
+ ///
+ public int Index { get; set; }
+
+ ///
+ /// PLMN标识
+ ///
+ public string Plmn { get; set; }
+
+ ///
+ /// 核心网配置
+ ///
+ public string CoreNetworkConfiguration { get; set; }
+
+ ///
+ /// IMS服务配置
+ ///
+ public string ImsServiceConfiguration { get; set; }
}
+ ```
- // 基础设施实现
- public class DeviceService : IDeviceService
+4. **设计优势**:
+ - **命名规范**:遵循C#命名约定,使用PascalCase
+ - **命名清晰**:类名明确表达业务含义,提高代码可读性
+ - **属性专业**:使用完整的专业术语,避免缩写和模糊命名
+ - **类型安全**:使用强类型属性,避免类型错误
+ - **文档完整**:每个属性都有详细的XML文档注释
+ - **集合初始化**:使用集合初始化器确保集合不为null
+ - **职责清晰**:每个类都有明确的职责和用途
+ - **易于扩展**:结构清晰,便于后续添加新属性
+ - **业务导向**:类名直接反映业务领域概念
+ - **专业术语**:使用标准的电信网络术语,提高代码专业性
+
+### 添加蜂窝网络配置数据校验功能
+
+**修改时间**: 2024年
+**修改文件**:
+- `CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs`
+
+**修改内容**:
+
+1. **添加数据校验功能**
+ - 为 `DeviceCode` 和 `RuntimeCode` 添加 `[Required]` 特性,确保不能为空
+ - 为 `Plmn` 添加 `[Required]` 特性,确保不能为空
+ - 添加 `ValidateConfiguration()` 方法进行业务逻辑校验
+
+2. **业务规则校验**
+ - 验证 `DeviceCode` 和 `RuntimeCode` 不能为空
+ - 验证 `RadioAccessNetworkConfiguration` 和 `CoreNetworkImsConfigurations` 至少有一个有数据
+ - 验证 `CoreNetworkImsConfiguration` 中的 `CoreNetworkConfiguration` 和 `ImsServiceConfiguration` 至少有一个有数据
+
+3. **创建ValidationResult类**
+ - 提供统一的验证结果返回格式
+ - 支持成功和失败两种状态
+ - 提供详细的错误消息
+ - 支持隐式转换操作符
+
+4. **具体实现**:
+ ```csharp
+ // 必填字段校验
+ [Required(ErrorMessage = "设备代码不能为空")]
+ public string DeviceCode { get; set; }
+
+ [Required(ErrorMessage = "运行时代码不能为空")]
+ public string RuntimeCode { get; set; }
+
+ // 业务逻辑校验
+ public ValidationResult ValidateConfiguration()
{
- private readonly ISystemCommandExecutor _commandExecutor;
-
- public async Task GetSerialNumberAsync()
+ // 验证必填字段
+ if (string.IsNullOrWhiteSpace(DeviceCode))
{
- string command = GetSerialNumberCommand();
- var result = await _commandExecutor.ExecuteCommandAsync(command, new CancellationTokenSource(), 5000);
- return ParseSerialNumber(result.Output);
+ return new ValidationResult("设备代码不能为空");
}
- }
- // 应用层处理器
- public async Task> Handle(GetSerialNumberCommand request, CancellationToken cancellationToken)
- {
- var deviceInfo = await _deviceService.GetSerialNumberAsync();
- return ApiActionResult.Ok(deviceInfo, "获取设备序列号成功");
- }
+ // 验证无线接入网配置和核心网IMS配置至少有一个有数据
+ var hasRadioAccessConfig = !string.IsNullOrWhiteSpace(RadioAccessNetworkConfiguration);
+ var hasCoreNetworkConfigs = CoreNetworkImsConfigurations?.Any() == true;
- // API控制器
- [HttpGet("serial-number")]
- public async Task GetSerialNumber()
- {
- var command = new GetSerialNumberCommand();
- var result = await _mediator.Send(command);
- return result;
+ if (!hasRadioAccessConfig && !hasCoreNetworkConfigs)
+ {
+ return new ValidationResult("无线接入网配置和核心网IMS配置至少需要配置其中一项");
+ }
+
+ return ValidationResult.Success;
}
```
-7. **设计优势**:
- - **DDD架构**: 严格遵循领域驱动设计的分层架构
- - **依赖倒置**: 高层模块依赖抽象,不依赖具体实现
- - **单一职责**: 每个类都有明确的职责
- - **跨平台支持**: 自动识别操作系统并使用对应命令
- - **错误处理**: 完善的异常处理和日志记录
- - **可测试性**: 接口抽象便于单元测试
- - **可扩展性**: 易于添加新的设备信息获取功能
+5. **设计优势**:
+ - **数据完整性**:确保必填字段不为空
+ - **业务规则校验**:验证业务逻辑的正确性
+ - **统一验证接口**:提供一致的验证方法
+ - **详细错误信息**:提供具体的错误描述
+ - **分层校验**:支持嵌套对象的校验
+ - **易于扩展**:可以轻松添加新的校验规则
**影响范围**:
-- 新增系统服务模块
-- 扩展API接口
-- 依赖注入配置更新
-- 命令处理流程扩展
+- 蜂窝网络配置数据模型定义
+- 核心网IMS配置管理
+- 数据实体结构标准化
+- 领域模型完整性
+- 代码可读性和维护性提升
+- 数据校验和业务规则验证
+- 错误处理和用户反馈
### 创建MessageTransferProtocolLog模型解决命名冲突
@@ -851,136 +907,333 @@
- 中间件的实例化策略
- 性能和内存使用优化
-### DeviceInfo模型添加IsSuccess字段和ParseSerialNumber方法优化
+### NetworkConfigCopier方法Bug修复和日志增强
+
+**修改时间**: 2024年
+**修改文件**:
+- `CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs`
+- `CoreAgent.Domain/Models/Network/NetworkConfigCopyResult.cs`
+- `CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs`
+
+**修改内容**:
+
+1. **返回类型统一化**
+ - **统一返回类型**:所有方法都返回 `NetworkConfigCopyResult` 类型,不再抛出异常
+ - **泛型结果类型**:创建 `NetworkConfigCopyResult` 泛型类,支持返回数据
+ - **接口更新**:更新 `INetworkConfigCopier` 接口以匹配新的返回类型
+ - **错误处理改进**:使用结果对象而不是异常来处理错误情况
+
+2. **CreateCellularNetworkConfigurationFile方法修复**
+ - **返回类型修改**:从 `Task` 改为 `Task`
+ - **路径构建Bug修复**:修复 `Path.Combine` 使用不当的问题,正确构建文件路径
+ - **参数验证增强**:添加完整的参数空值检查,返回失败结果而不是抛出异常
+ - **目录创建**:确保目标目录存在,避免文件写入失败
+ - **详细日志**:添加每个步骤的详细日志记录,包括开始、成功、警告和错误信息
+
+3. **CreateRadioAccessNetworkConfigurationFile方法修复**
+ - **返回类型修改**:从 `Task` 改为 `Task`
+ - **参数命名规范化**:使用小写开头的参数名,符合C#命名约定
+ - **目录创建逻辑**:添加目录存在性检查和自动创建
+ - **错误处理增强**:返回失败结果而不是抛出异常
+ - **参数验证**:验证文件路径和配置内容不为空
+
+4. **CreateCoreNetworkImsConfigurationFiles方法重构**
+ - **返回类型修改**:从 `Task>` 改为 `Task>>`
+ - **方法重命名**:避免与RAN配置文件创建方法名冲突
+ - **参数验证完善**:验证RuntimeCode、配置列表和AppSettings
+ - **配置项验证**:验证每个配置项的PLMN和配置内容
+ - **目录创建**:为CN和IMS配置文件分别创建目录
+ - **错误隔离**:单个配置项失败不影响其他配置项处理
+ - **详细日志**:记录每个配置项的处理过程和结果
+
+5. **DeleteCellularNetworkConfigurationFile方法增强**
+ - **返回类型修改**:从 `bool` 改为 `NetworkConfigCopyResult`
+ - **文件存在性检查**:删除前检查文件是否存在,避免异常
+ - **错误隔离**:单个文件删除失败不影响其他文件删除
+ - **删除统计**:统计成功删除的文件数量
+ - **详细日志**:记录每个文件的删除状态和结果
+ - **参数验证**:验证NetworkConfiguration参数不为空
+
+6. **NetworkConfigCopyResult类扩展**
+ - **泛型支持**:添加 `NetworkConfigCopyResult` 泛型类
+ - **数据返回**:支持返回操作结果的同时返回数据
+ - **继承关系**:泛型类继承自基础类,保持类型安全
+ - **静态工厂方法**:提供 `Success(T data)` 和 `Failure(string errorMessage)` 方法
+
+7. **具体修复的Bug**:
+ ```csharp
+ // 修复前 - 路径构建错误
+ string RanConfigPath = $"{appSettings.RanConfigDirectory}{Path.Combine("RAN", $"{cellular.RuntimeCode}.cfg")}";
+
+ // 修复后 - 正确的路径构建
+ string ranConfigPath = Path.Combine(appSettings.RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg");
+
+ // 修复前 - 抛出异常
+ throw new ArgumentNullException(nameof(cellular));
+
+ // 修复后 - 返回失败结果
+ return NetworkConfigCopyResult.Failure("CellularNetworkConfiguration 参数为空");
+
+ // 修复前 - 返回原始类型
+ public async Task CreateCellularNetworkConfigurationFile(...)
+
+ // 修复后 - 返回结果类型
+ public async Task CreateCellularNetworkConfigurationFile(...)
+ ```
+
+8. **设计优势**:
+ - **统一错误处理**:所有方法都使用结果对象,避免异常传播
+ - **类型安全**:泛型结果类型确保类型安全
+ - **Bug修复**:修复路径构建、方法名冲突、文件删除等关键Bug
+ - **错误处理完善**:添加完整的错误处理和错误隔离机制
+ - **日志详细**:提供完整的操作跟踪和调试信息
+ - **参数验证**:确保所有输入参数的有效性
+ - **目录管理**:自动创建必要的目录结构
+ - **错误隔离**:单个操作失败不影响整体流程
+ - **命名规范**:遵循C#命名约定,提高代码可读性
+ - **方法职责清晰**:每个方法都有明确的职责和边界
+
+9. **修复的关键问题**:
+ - **异常处理不一致**:统一使用结果对象而不是异常
+ - **路径构建错误**:`Path.Combine` 使用不当导致路径错误
+ - **方法名冲突**:两个不同功能的方法使用相同名称
+ - **文件删除异常**:删除不存在的文件导致异常
+ - **目录不存在**:目标目录不存在导致文件写入失败
+ - **错误传播**:单个错误导致整个操作失败
+ - **日志缺失**:缺少关键操作的日志记录
+
+**影响范围**:
+- 网络配置文件创建和删除的稳定性
+- 错误处理和异常预防
+- 日志记录和调试能力
+- 代码可读性和维护性
+- 文件系统操作的可靠性
+- 配置管理的完整性
+- 接口契约的一致性
+- 调用方代码的错误处理方式
+
+### NetworkConfigCopier返回类型优化和GeneralCellularNetworkService适配
**修改时间**: 2024年
**修改文件**:
-- `CoreAgent.Domain/Models/System/DeviceInfo.cs`
-- `CoreAgent.Domain/Models/System/DeviceInfoResponse.cs` (新建)
-- `CoreAgent.Infrastructure/Services/System/DeviceService.cs`
-- `CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs`
-- `CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs`
+- `CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs`
+- `CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs`
+- `CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs`
**修改内容**:
-1. **DeviceInfo模型添加IsSuccess字段**
- - 添加 `bool IsSuccess { get; set; }` 属性
- - 用于标识是否成功获取到序列号
- - 提供更准确的成功/失败状态判断
-
-2. **创建DeviceInfoResponse模型**
- - 创建专门用于API响应的模型
- - 只包含 `SerialNumber` 和 `Timestamp` 字段
- - 不包含内部状态字段 `IsSuccess`
- - 确保API响应简洁明了
-
-2. **ParseSerialNumber方法优化**
- - 返回类型从 `string` 改为 `string?`(可空字符串)
- - 失败时返回 `null` 而不是固定字符串
- - 修复Linux系统输出格式解析:`Serial Number: xxxxxxxx`
- - 添加更详细的注释说明返回值含义
-
-3. **DeviceService方法更新**
- - 修改异步和同步方法中的DeviceInfo创建逻辑
- - 根据ParseSerialNumber返回值设置IsSuccess字段
- - 成功时设置 `IsSuccess = true`
- - 失败时设置 `IsSuccess = false`
- - 添加更详细的日志记录
-
-4. **GetSerialNumberCommand和GetSerialNumberCommandHandler优化**
- - 修改命令返回类型为 `ApiActionResult`
- - 在Handle方法中检查 `deviceInfo.IsSuccess` 字段
- - 成功时创建 `DeviceInfoResponse` 对象返回,不包含IsSuccess字段
- - 失败时返回 `ApiActionResult.Error()` 并设置错误代码 `DEVICE_SN_NOT_FOUND`
- - 提供更准确的错误信息
- - 确保API返回的响应模型不包含内部状态字段
+1. **CreateCellularNetworkConfigurationFile返回类型优化**
+ - **返回类型修改**:从 `Task` 改为 `Task>`
+ - **数据返回**:成功时返回包含 `NetworkConfiguration` 对象的结果
+ - **接口更新**:更新接口定义以匹配新的返回类型
+ - **调用方适配**:修改调用方代码以正确使用返回的数据
-5. **具体实现**:
+2. **GeneralCellularNetworkService调用修复**
+ - **返回类型适配**:修改调用方式以适配新的泛型返回类型
+ - **数据获取**:直接从结果对象的 `Data` 属性获取 `NetworkConfiguration`
+ - **错误处理改进**:使用 `IsSuccess` 属性检查操作是否成功
+ - **代码简化**:移除手动创建 `NetworkConfiguration` 的代码
+
+3. **接口定义更新**
+ - **泛型支持**:接口方法返回 `Task>`
+ - **文档更新**:更新XML文档注释说明返回的数据类型
+
+4. **具体修改**:
+ ```csharp
+ // NetworkConfigCopier.cs - 返回类型修改
+ // 修复前
+ public async Task CreateCellularNetworkConfigurationFile(...)
+ {
+ // ... 创建NetworkConfiguration对象
+ return NetworkConfigCopyResult.Success(); // 没有返回数据
+ }
+
+ // 修复后
+ public async Task> CreateCellularNetworkConfigurationFile(...)
+ {
+ // ... 创建NetworkConfiguration对象
+ return NetworkConfigCopyResult.Success(network); // 返回数据
+ }
+
+ // GeneralCellularNetworkService.cs - 调用修复
+ // 修复前 - 手动创建配置对象
+ var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings());
+ if (!createResult.IsSuccess)
+ {
+ return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}");
+ }
+
+ var config = NetworkConfiguration.Create(cellular.RuntimeCode,
+ Path.Combine(_context.GetAppSettings().RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg"),
+ new List());
+
+ // 修复后 - 直接使用返回的数据
+ var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings());
+ if (!createResult.IsSuccess)
+ {
+ return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}");
+ }
+
+ var config = createResult.Data; // 直接获取返回的NetworkConfiguration对象
+ ```
+
+5. **设计优势**:
+ - **数据完整性**:返回完整的 `NetworkConfiguration` 对象,包含所有配置信息
+ - **类型安全**:泛型结果类型确保类型安全
+ - **代码简化**:调用方无需手动创建配置对象
+ - **错误处理统一**:保持统一的错误处理模式
+ - **接口一致性**:接口和实现保持完全一致
+
+6. **修复的关键问题**:
+ - **数据丢失**:原方法创建了 `NetworkConfiguration` 但没有返回
+ - **代码重复**:调用方需要手动创建配置对象
+ - **类型不匹配**:返回类型与实际需求不匹配
+ - **接口不一致**:接口定义与实际实现不一致
+
+**影响范围**:
+- 网络配置创建流程的数据完整性
+- 调用方代码的简化
+- 接口契约的一致性
+- 类型安全和错误处理
+
+### 修改CreateCellularNetworkConfigurationFile为元组返回
+
+**修改时间**: 2024年
+**修改文件**:
+- `CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs`
+- `CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs`
+- `CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs`
+
+**修改内容**:
+
+1. **修改CreateCellularNetworkConfigurationFile返回类型**
+ - 将返回类型从 `Task>` 改为元组 `Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)>`
+ - 简化返回结构,直接返回三个值:是否成功、错误信息、网络配置对象
+
+2. **更新接口定义**
+ - 更新 `INetworkConfigCopier` 接口中的方法签名
+ - 更新XML文档注释说明新的返回类型
+
+3. **更新调用代码**
+ - 修改 `GeneralCellularNetworkService.cs` 中的调用逻辑
+ - 使用元组解构语法 `var (isSuccess, errorMessage, config) = await ...`
+ - 直接使用解构后的变量
+
+4. **具体实现**:
```csharp
- // DeviceInfo模型(内部使用)
- public class DeviceInfo
+ // 修改前
+ public async Task> CreateCellularNetworkConfigurationFile(...)
{
- public bool IsSuccess { get; set; }
- public string SerialNumber { get; set; } = string.Empty;
- public DateTime Timestamp { get; set; } = DateTime.UtcNow;
+ return NetworkConfigCopyResult.Failure("错误信息");
+ return NetworkConfigCopyResult.Success(network);
}
- // DeviceInfoResponse模型(API响应)
- public class DeviceInfoResponse
+ // 修改后
+ public async Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)> CreateCellularNetworkConfigurationFile(...)
{
- public string SerialNumber { get; set; } = string.Empty;
- public DateTime Timestamp { get; set; } = DateTime.UtcNow;
+ return (false, "错误信息", null);
+ return (true, null, network);
}
+ ```
- // ParseSerialNumber方法
- private string? ParseSerialNumber(string output)
+5. **调用代码修改**:
+ ```csharp
+ // 修改前
+ var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings());
+ if (!createResult.IsSuccess)
{
- if (string.IsNullOrWhiteSpace(output))
- return null;
+ return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}");
+ }
+ var config = createResult.Data;
- foreach (var line in lines)
- {
- if (OperatingSystem.IsLinux())
- {
- // Linux输出格式: Serial Number: xxxxxxxx
- if (trimmedLine.StartsWith("Serial Number:", StringComparison.OrdinalIgnoreCase))
- {
- var serialNumber = trimmedLine.Substring("Serial Number:".Length).Trim();
- return string.IsNullOrWhiteSpace(serialNumber) ? null : serialNumber;
- }
- }
- }
- return null;
+ // 修改后
+ var (isSuccess, errorMessage, config) = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings());
+ if (!isSuccess)
+ {
+ return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {errorMessage}");
}
+ ```
+
+6. **设计优势**:
+ - **简洁性**:元组返回比包装类更简洁
+ - **直观性**:直接返回三个值,语义更清晰
+ - **性能**:避免创建额外的包装对象
+ - **易用性**:使用元组解构语法,代码更简洁
+ - **类型安全**:保持强类型,编译时检查
+
+**影响范围**:
+- 网络配置创建方法的返回类型简化
+- 调用代码的简化
+- 接口定义的更新
+- 代码可读性的提升
+
+### 修改CreateCoreNetworkImsConfigurationFiles为元组返回
+
+**修改时间**: 2024年
+**修改文件**:
+- `CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs`
+
+**修改内容**:
+
+1. **修改CreateCoreNetworkImsConfigurationFiles返回类型**
+ - 将返回类型从 `Task>>` 改为元组 `Task<(bool IsSuccess, string ErrorMessage, List CoreImsConfigs)>`
+ - 简化返回结构,直接返回三个值:是否成功、错误信息、核心IMS配置列表
+
+2. **更新调用代码**
+ - 修改 `CreateCellularNetworkConfigurationFile` 方法中对 `CreateCoreNetworkImsConfigurationFiles` 的调用
+ - 使用元组解构语法 `var (coreImsSuccess, coreImsError, coreImsConfigs) = await ...`
+ - 直接使用解构后的变量
- // DeviceService中的使用
- if (serialNumber != null)
+3. **具体实现**:
+ ```csharp
+ // 修改前
+ public async Task>> CreateCoreNetworkImsConfigurationFiles(...)
{
- return new DeviceInfo
- {
- IsSuccess = true,
- SerialNumber = serialNumber,
- Timestamp = DateTime.UtcNow
- };
+ return NetworkConfigCopyResult>.Failure("错误信息");
+ return NetworkConfigCopyResult>.Success(list);
}
- else
+
+ // 修改后
+ public async Task<(bool IsSuccess, string ErrorMessage, List CoreImsConfigs)> CreateCoreNetworkImsConfigurationFiles(...)
{
- return new DeviceInfo
- {
- IsSuccess = false,
- SerialNumber = "UNKNOWN",
- Timestamp = DateTime.UtcNow
- };
+ return (false, "错误信息", null);
+ return (true, null, list);
}
+ ```
- // GetSerialNumberCommandHandler中的使用
- if (deviceInfo.IsSuccess)
+4. **调用代码修改**:
+ ```csharp
+ // 修改前
+ var coreImsResult = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings);
+ if (!coreImsResult.IsSuccess)
{
- // 创建DeviceInfoResponse对象,不包含IsSuccess字段
- var resultDeviceInfo = new DeviceInfoResponse
- {
- SerialNumber = deviceInfo.SerialNumber,
- Timestamp = deviceInfo.Timestamp
- };
- return ApiActionResult.Ok(resultDeviceInfo, "获取设备序列号成功");
+ return (false, $"创建核心网络和IMS配置文件失败: {coreImsResult.ErrorMessage}", null);
}
- else
+ list = coreImsResult.Data;
+
+ // 修改后
+ var (coreImsSuccess, coreImsError, coreImsConfigs) = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings);
+ if (!coreImsSuccess)
{
- return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND");
+ return (false, $"创建核心网络和IMS配置文件失败: {coreImsError}", null);
}
+ list = coreImsConfigs;
```
-6. **设计优势**:
- - **准确的状态判断**:通过IsSuccess字段明确标识操作结果
- - **更好的错误处理**:区分不同类型的失败情况
- - **Linux兼容性**:正确解析Linux系统的序列号输出格式
- - **空值安全**:使用可空字符串避免固定错误字符串
- - **详细日志**:提供更丰富的日志信息便于调试
- - **API一致性**:返回统一的ApiActionResult格式
+5. **设计优势**:
+ - **一致性**:与 `CreateCellularNetworkConfigurationFile` 方法保持相同的返回模式
+ - **简洁性**:元组返回比包装类更简洁
+ - **直观性**:直接返回三个值,语义更清晰
+ - **性能**:避免创建额外的包装对象
+ - **易用性**:使用元组解构语法,代码更简洁
+
+6. **接口说明**:
+ - `CreateCoreNetworkImsConfigurationFiles` 是内部方法,不在接口中定义
+ - 只在 `NetworkConfigCopier` 实现类中使用
+ - 保持接口的简洁性
**影响范围**:
-- 设备序列号获取的准确性
-- API响应的错误处理
-- Linux系统兼容性
-- 日志记录的详细程度
-- 客户端错误处理逻辑
\ No newline at end of file
+- 核心网络和IMS配置文件创建方法的返回类型简化
+- 内部方法调用代码的简化
+- 代码一致性的提升
+- 性能的优化
\ No newline at end of file