From fee41aaf7d8313297fa9333b063bafca988cedcf Mon Sep 17 00:00:00 2001 From: hyh Date: Tue, 29 Jul 2025 14:43:40 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=BA=8F=E5=88=97=E5=8F=B7=E8=8E=B7=E5=8F=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E9=81=B5=E5=BE=AADDD=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增DeviceInfo模型,包含IsSuccess字段用于状态判断 - 实现IDeviceService接口和DeviceService实现类 - 支持Windows和Linux系统序列号获取 - 修复ParseSerialNumber方法,支持Linux输出格式解析 - 创建GetSerialNumberCommand和GetSerialNumberCommandHandler - 添加SystemController API控制器 - 修复CS0234编译错误,添加System.Net引用 - 更新依赖注入配置 - 完善错误处理和日志记录 --- CoreAgent.API/Controllers/SystemController.cs | 34 +++ .../Commands/System/GetSerialNumberCommand.cs | 13 ++ .../StartCellularNetworkCommandHandler.cs | 5 +- .../StopCellularNetworkCommandHandler.cs | 5 +- ...reateNetworkConfigurationCommandHandler.cs | 5 +- ...eleteNetworkConfigurationCommandHandler.cs | 5 +- ...GetAllNetworkConfigurationsQueryHandler.cs | 3 +- ...etNetworkConfigurationByKeyQueryHandler.cs | 5 +- .../System/GetSerialNumberCommandHandler.cs | 51 ++++ .../Interfaces/System/IDeviceService.cs | 21 ++ CoreAgent.Domain/Models/System/DeviceInfo.cs | 22 ++ .../CommandServiceExtensions.cs | 5 + .../Network/NetworkProtocolLogObserver.cs | 2 +- .../Services/System/DeviceService.cs | 217 ++++++++++++++++++ .../Models/MessageTransferProtocolLog.cs | 2 +- modify.md | 216 ++++++++++++++++- 16 files changed, 597 insertions(+), 14 deletions(-) create mode 100644 CoreAgent.API/Controllers/SystemController.cs create mode 100644 CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs create mode 100644 CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs create mode 100644 CoreAgent.Domain/Interfaces/System/IDeviceService.cs create mode 100644 CoreAgent.Domain/Models/System/DeviceInfo.cs create mode 100644 CoreAgent.Infrastructure/Services/System/DeviceService.cs diff --git a/CoreAgent.API/Controllers/SystemController.cs b/CoreAgent.API/Controllers/SystemController.cs new file mode 100644 index 0000000..df86215 --- /dev/null +++ b/CoreAgent.API/Controllers/SystemController.cs @@ -0,0 +1,34 @@ +using CoreAgent.Application.Commands.System; +using CoreAgent.Domain.Models.System; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace CoreAgent.API.Controllers; + +/// +/// 系统控制器 +/// +public class SystemController : BaseApiController +{ + public SystemController(IMediator mediator, ILogger logger) + : base(mediator, logger) + { + } + + /// + /// 获取设备序列号(SN) + /// + /// 设备信息 + [HttpGet("serial-number")] + public async Task GetSerialNumber() + { + _logger.LogInformation("收到获取设备序列号请求"); + + var command = new GetSerialNumberCommand(); + var result = await _mediator.Send(command); + + _logger.LogInformation("成功返回设备序列号: {SerialNumber}", result.Data?.SerialNumber); + + return result; + } +} \ No newline at end of file diff --git a/CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs b/CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs new file mode 100644 index 0000000..932e356 --- /dev/null +++ b/CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs @@ -0,0 +1,13 @@ +using CoreAgent.Domain.Models.Common; +using CoreAgent.Domain.Models.System; +using MediatR; + +namespace CoreAgent.Application.Commands.System; + +/// +/// 获取设备序列号命令 +/// +public class GetSerialNumberCommand : IRequest> +{ + // 命令不需要额外参数,直接获取当前设备的序列号 +} \ No newline at end of file diff --git a/CoreAgent.Application/Handlers/CellularNetwork/StartCellularNetworkCommandHandler.cs b/CoreAgent.Application/Handlers/CellularNetwork/StartCellularNetworkCommandHandler.cs index 403f520..3061c7b 100644 --- a/CoreAgent.Application/Handlers/CellularNetwork/StartCellularNetworkCommandHandler.cs +++ b/CoreAgent.Application/Handlers/CellularNetwork/StartCellularNetworkCommandHandler.cs @@ -4,6 +4,7 @@ using CoreAgent.Domain.Models.Common; using CoreAgent.Domain.Models.Network; using MediatR; using Microsoft.Extensions.Logging; +using System.Net; namespace CoreAgent.Application.Handlers.CellularNetwork; @@ -43,7 +44,7 @@ public class StartCellularNetworkCommandHandler : IRequestHandler.Error( result.ErrorMessage, "NETWORK_START_ERROR", - System.Net.HttpStatusCode.BadRequest); + HttpStatusCode.BadRequest); } } catch (Exception ex) @@ -52,7 +53,7 @@ public class StartCellularNetworkCommandHandler : IRequestHandler.Error( $"启动蜂窝网络失败: {ex.Message}", "INTERNAL_ERROR", - System.Net.HttpStatusCode.InternalServerError); + HttpStatusCode.InternalServerError); } } } \ No newline at end of file diff --git a/CoreAgent.Application/Handlers/CellularNetwork/StopCellularNetworkCommandHandler.cs b/CoreAgent.Application/Handlers/CellularNetwork/StopCellularNetworkCommandHandler.cs index 648ffd6..6beb7e6 100644 --- a/CoreAgent.Application/Handlers/CellularNetwork/StopCellularNetworkCommandHandler.cs +++ b/CoreAgent.Application/Handlers/CellularNetwork/StopCellularNetworkCommandHandler.cs @@ -3,6 +3,7 @@ using CoreAgent.Domain.Interfaces.Network; using CoreAgent.Domain.Models.Common; using MediatR; using Microsoft.Extensions.Logging; +using System.Net; namespace CoreAgent.Application.Handlers.CellularNetwork; @@ -42,7 +43,7 @@ public class StopCellularNetworkCommandHandler : IRequestHandler.Error( result.ErrorMessage, "NETWORK_STOP_ERROR", - System.Net.HttpStatusCode.BadRequest); + HttpStatusCode.BadRequest); } } catch (Exception ex) @@ -51,7 +52,7 @@ public class StopCellularNetworkCommandHandler : IRequestHandler.Error( $"停止蜂窝网络失败: {ex.Message}", "INTERNAL_ERROR", - System.Net.HttpStatusCode.InternalServerError); + HttpStatusCode.InternalServerError); } } } \ No newline at end of file diff --git a/CoreAgent.Application/Handlers/NetworkConfig/Commands/CreateNetworkConfigurationCommandHandler.cs b/CoreAgent.Application/Handlers/NetworkConfig/Commands/CreateNetworkConfigurationCommandHandler.cs index 5ffb2c3..1c4e42a 100644 --- a/CoreAgent.Application/Handlers/NetworkConfig/Commands/CreateNetworkConfigurationCommandHandler.cs +++ b/CoreAgent.Application/Handlers/NetworkConfig/Commands/CreateNetworkConfigurationCommandHandler.cs @@ -1,4 +1,5 @@ using System; +using System.Net; using System.Threading; using System.Threading.Tasks; using CoreAgent.Application.Commands.NetworkConfig; @@ -63,7 +64,7 @@ namespace CoreAgent.Application.Handlers.NetworkConfig.Commands return ApiActionResult.Error( "配置键已存在", "CONFIG_KEY_EXISTS", - System.Net.HttpStatusCode.Conflict); + HttpStatusCode.Conflict); } } catch (Exception ex) @@ -72,7 +73,7 @@ namespace CoreAgent.Application.Handlers.NetworkConfig.Commands return ApiActionResult.Error( $"创建网络配置失败: {ex.Message}", "INTERNAL_ERROR", - System.Net.HttpStatusCode.InternalServerError); + HttpStatusCode.InternalServerError); } } } diff --git a/CoreAgent.Application/Handlers/NetworkConfig/Commands/DeleteNetworkConfigurationCommandHandler.cs b/CoreAgent.Application/Handlers/NetworkConfig/Commands/DeleteNetworkConfigurationCommandHandler.cs index 55f47c9..6e83b28 100644 --- a/CoreAgent.Application/Handlers/NetworkConfig/Commands/DeleteNetworkConfigurationCommandHandler.cs +++ b/CoreAgent.Application/Handlers/NetworkConfig/Commands/DeleteNetworkConfigurationCommandHandler.cs @@ -1,4 +1,5 @@ using System; +using System.Net; using System.Threading; using System.Threading.Tasks; using CoreAgent.Application.Commands.NetworkConfig; @@ -55,7 +56,7 @@ namespace CoreAgent.Application.Handlers.NetworkConfig.Commands return ApiActionResult.Error( "未找到要删除的网络配置", "CONFIG_NOT_FOUND", - System.Net.HttpStatusCode.NotFound); + HttpStatusCode.NotFound); } } catch (Exception ex) @@ -64,7 +65,7 @@ namespace CoreAgent.Application.Handlers.NetworkConfig.Commands return ApiActionResult.Error( $"删除网络配置失败: {ex.Message}", "INTERNAL_ERROR", - System.Net.HttpStatusCode.InternalServerError); + HttpStatusCode.InternalServerError); } } } diff --git a/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetAllNetworkConfigurationsQueryHandler.cs b/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetAllNetworkConfigurationsQueryHandler.cs index 460c60a..8ffbd09 100644 --- a/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetAllNetworkConfigurationsQueryHandler.cs +++ b/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetAllNetworkConfigurationsQueryHandler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net; using System.Threading; using System.Threading.Tasks; using CoreAgent.Application.Commands.NetworkConfig; @@ -55,7 +56,7 @@ namespace CoreAgent.Application.Handlers.NetworkConfig.Commands return ApiActionResult>.Error( $"获取所有网络配置失败: {ex.Message}", "INTERNAL_ERROR", - System.Net.HttpStatusCode.InternalServerError); + HttpStatusCode.InternalServerError); } } } diff --git a/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetNetworkConfigurationByKeyQueryHandler.cs b/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetNetworkConfigurationByKeyQueryHandler.cs index 88d2e92..2373c7a 100644 --- a/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetNetworkConfigurationByKeyQueryHandler.cs +++ b/CoreAgent.Application/Handlers/NetworkConfig/Commands/GetNetworkConfigurationByKeyQueryHandler.cs @@ -1,4 +1,5 @@ using System; +using System.Net; using System.Threading; using System.Threading.Tasks; using CoreAgent.Application.Commands.NetworkConfig; @@ -50,7 +51,7 @@ namespace CoreAgent.Application.Handlers.NetworkConfig.Commands return ApiActionResult.Error( $"未找到网络配置: {request.ConfigKey}", "CONFIG_NOT_FOUND", - System.Net.HttpStatusCode.NotFound); + HttpStatusCode.NotFound); } _logger.LogInformation("成功获取网络配置: {ConfigKey}", request.ConfigKey); @@ -62,7 +63,7 @@ namespace CoreAgent.Application.Handlers.NetworkConfig.Commands return ApiActionResult.Error( $"获取网络配置失败: {ex.Message}", "INTERNAL_ERROR", - System.Net.HttpStatusCode.InternalServerError); + HttpStatusCode.InternalServerError); } } } diff --git a/CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs b/CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs new file mode 100644 index 0000000..249c697 --- /dev/null +++ b/CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs @@ -0,0 +1,51 @@ +using CoreAgent.Application.Commands.System; +using CoreAgent.Domain.Interfaces.System; +using CoreAgent.Domain.Models.Common; +using CoreAgent.Domain.Models.System; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace CoreAgent.Application.Handlers.System; + +/// +/// 获取设备序列号命令处理器 +/// +public class GetSerialNumberCommandHandler : IRequestHandler> +{ + private readonly IDeviceService _deviceService; + private readonly ILogger _logger; + + public GetSerialNumberCommandHandler( + IDeviceService deviceService, + ILogger logger) + { + _deviceService = deviceService ?? throw new ArgumentNullException(nameof(deviceService)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + public async Task> Handle(GetSerialNumberCommand request, CancellationToken cancellationToken) + { + try + { + _logger.LogInformation("开始处理获取设备序列号命令"); + + var deviceInfo = await _deviceService.GetSerialNumberAsync(); + + if (deviceInfo.IsSuccess) + { + _logger.LogInformation("成功获取设备序列号: {SerialNumber}", deviceInfo.SerialNumber); + return ApiActionResult.Ok(deviceInfo, "获取设备序列号成功"); + } + else + { + _logger.LogWarning("获取设备序列号失败,返回的序列号: {SerialNumber}", deviceInfo.SerialNumber); + return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND"); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "处理获取设备序列号命令时发生异常"); + return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_ERROR"); + } + } +} \ No newline at end of file diff --git a/CoreAgent.Domain/Interfaces/System/IDeviceService.cs b/CoreAgent.Domain/Interfaces/System/IDeviceService.cs new file mode 100644 index 0000000..bf999af --- /dev/null +++ b/CoreAgent.Domain/Interfaces/System/IDeviceService.cs @@ -0,0 +1,21 @@ +using CoreAgent.Domain.Models.System; + +namespace CoreAgent.Domain.Interfaces.System; + +/// +/// 设备服务接口 +/// +public interface IDeviceService +{ + /// + /// 获取设备序列号(SN) + /// + /// 设备信息 + Task GetSerialNumberAsync(); + + /// + /// 获取设备序列号(SN)- 同步版本 + /// + /// 设备信息 + DeviceInfo GetSerialNumber(); +} \ No newline at end of file diff --git a/CoreAgent.Domain/Models/System/DeviceInfo.cs b/CoreAgent.Domain/Models/System/DeviceInfo.cs new file mode 100644 index 0000000..cab3cf9 --- /dev/null +++ b/CoreAgent.Domain/Models/System/DeviceInfo.cs @@ -0,0 +1,22 @@ +namespace CoreAgent.Domain.Models.System; + +/// +/// 设备信息模型 +/// +public class DeviceInfo +{ + /// + /// 是否成功获取到序列号 + /// + public bool IsSuccess { get; set; } + + /// + /// 设备序列号(SN) + /// + public string SerialNumber { get; set; } = string.Empty; + + /// + /// 获取时间 + /// + public DateTime Timestamp { get; set; } = DateTime.UtcNow; +} \ No newline at end of file diff --git a/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs b/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs index c37e5a8..5bd9615 100644 --- a/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs +++ b/CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs @@ -1,11 +1,13 @@ using CoreAgent.Domain.Interfaces; using CoreAgent.Domain.Interfaces.Network; +using CoreAgent.Domain.Interfaces.System; 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; +using CoreAgent.Infrastructure.Services.System; using CoreAgent.ProtocolClient.Interfaces; using CoreAgent.ProtocolClient.ProtocolEngineCore; using Microsoft.Extensions.DependencyInjection; @@ -57,6 +59,9 @@ public static class CommandServiceExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + + // 注册系统服务 + services.AddScoped(); return services; } diff --git a/CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs b/CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs index 760a56c..89e3454 100644 --- a/CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs +++ b/CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs @@ -50,7 +50,7 @@ namespace CoreAgent.Infrastructure.Services.Network var webSocketLogs = logList.Select(log => new MessageTransferProtocolLog { Id = log.Id, - LayerType = log.LayerType.ToString(), + LayerType = (int)log.LayerType, MessageDetailJson = log.MessageDetailJson, CellID = log.CellID, IMSI = log.IMSI, diff --git a/CoreAgent.Infrastructure/Services/System/DeviceService.cs b/CoreAgent.Infrastructure/Services/System/DeviceService.cs new file mode 100644 index 0000000..ea721bf --- /dev/null +++ b/CoreAgent.Infrastructure/Services/System/DeviceService.cs @@ -0,0 +1,217 @@ +using CoreAgent.Domain.Interfaces.System; +using CoreAgent.Domain.Interfaces.System.Command; +using CoreAgent.Domain.Models.System; +using Microsoft.Extensions.Logging; + +namespace CoreAgent.Infrastructure.Services.System; + +/// +/// 设备服务实现 +/// +public class DeviceService : IDeviceService +{ + private readonly ILogger _logger; + private readonly ISystemCommandExecutor _commandExecutor; + + public DeviceService( + ILogger logger, + ISystemCommandExecutor commandExecutor) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor)); + } + + /// + /// 获取设备序列号(SN) + /// + /// 设备信息 + public async Task GetSerialNumberAsync() + { + try + { + _logger.LogDebug("开始获取设备序列号"); + + // 根据操作系统选择不同的命令 + string command = GetSerialNumberCommand(); + + var result = await _commandExecutor.ExecuteCommandAsync(command, new CancellationTokenSource(), 5000); + + if (result.IsSuccess) + { + var serialNumber = ParseSerialNumber(result.Output); + if (serialNumber != null) + { + _logger.LogInformation("成功获取设备序列号: {SerialNumber}", serialNumber); + + return new DeviceInfo + { + IsSuccess = true, + SerialNumber = serialNumber, + Timestamp = DateTime.UtcNow + }; + } + else + { + _logger.LogWarning("解析设备序列号失败,输出内容: {Output}", result.Output); + return new DeviceInfo + { + IsSuccess = false, + SerialNumber = "UNKNOWN", + Timestamp = DateTime.UtcNow + }; + } + } + else + { + _logger.LogError("获取设备序列号失败: {Error}", result.Error); + return new DeviceInfo + { + IsSuccess = false, + SerialNumber = "UNKNOWN", + Timestamp = DateTime.UtcNow + }; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "获取设备序列号时发生异常"); + return new DeviceInfo + { + IsSuccess = false, + SerialNumber = "ERROR", + Timestamp = DateTime.UtcNow + }; + } + } + + /// + /// 获取设备序列号(SN)- 同步版本 + /// + /// 设备信息 + public DeviceInfo GetSerialNumber() + { + try + { + _logger.LogDebug("开始获取设备序列号(同步)"); + + // 根据操作系统选择不同的命令 + string command = GetSerialNumberCommand(); + + // 使用同步方式执行命令 + var task = _commandExecutor.ExecuteCommandAsync(command, new CancellationTokenSource(), 5000); + task.Wait(); + var result = task.Result; + + if (result.IsSuccess) + { + var serialNumber = ParseSerialNumber(result.Output); + if (serialNumber != null) + { + _logger.LogInformation("成功获取设备序列号: {SerialNumber}", serialNumber); + + return new DeviceInfo + { + IsSuccess = true, + SerialNumber = serialNumber, + Timestamp = DateTime.UtcNow + }; + } + else + { + _logger.LogWarning("解析设备序列号失败,输出内容: {Output}", result.Output); + return new DeviceInfo + { + IsSuccess = false, + SerialNumber = "UNKNOWN", + Timestamp = DateTime.UtcNow + }; + } + } + else + { + _logger.LogError("获取设备序列号失败: {Error}", result.Error); + return new DeviceInfo + { + IsSuccess = false, + SerialNumber = "UNKNOWN", + Timestamp = DateTime.UtcNow + }; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "获取设备序列号时发生异常"); + return new DeviceInfo + { + IsSuccess = false, + SerialNumber = "ERROR", + Timestamp = DateTime.UtcNow + }; + } + } + + /// + /// 根据操作系统获取序列号命令 + /// + /// 命令字符串 + private string GetSerialNumberCommand() + { + if (OperatingSystem.IsWindows()) + { + // Windows系统获取序列号命令 + return "wmic bios get serialnumber /value"; + } + else if (OperatingSystem.IsLinux()) + { + // Linux系统获取序列号命令 + return "smartctl -i /dev/nvme0n1|grep Serial"; + } + else + { + // 其他系统使用通用命令 + return "echo UNKNOWN"; + } + } + + /// + /// 解析序列号输出 + /// + /// 命令输出 + /// 解析后的序列号,失败时返回null + private string? ParseSerialNumber(string output) + { + if (string.IsNullOrWhiteSpace(output)) + { + return null; + } + + // 清理输出内容 + var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + + if (OperatingSystem.IsWindows()) + { + // Windows输出格式: SerialNumber=XXXXXXXX + if (trimmedLine.StartsWith("SerialNumber=", StringComparison.OrdinalIgnoreCase)) + { + var serialNumber = trimmedLine.Substring("SerialNumber=".Length).Trim(); + return string.IsNullOrWhiteSpace(serialNumber) ? null : serialNumber; + } + } + else 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; + } +} \ No newline at end of file diff --git a/CoreAgent.WebSocketTransport/Models/MessageTransferProtocolLog.cs b/CoreAgent.WebSocketTransport/Models/MessageTransferProtocolLog.cs index c063043..c1264f3 100644 --- a/CoreAgent.WebSocketTransport/Models/MessageTransferProtocolLog.cs +++ b/CoreAgent.WebSocketTransport/Models/MessageTransferProtocolLog.cs @@ -21,7 +21,7 @@ namespace CoreAgent.WebSocketTransport.Models /// /// 协议层类型 /// - public string LayerType { get; set; } = string.Empty; + public int LayerType { get; set; } /// /// 消息详情集合(JSON格式存储) diff --git a/modify.md b/modify.md index ab3fad4..a54ea75 100644 --- a/modify.md +++ b/modify.md @@ -2,6 +2,109 @@ ## 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` + +**修改内容**: + +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. **具体实现**: + ```csharp + // 领域模型 + public class DeviceInfo + { + public string SerialNumber { get; set; } = string.Empty; + public DateTime Timestamp { get; set; } = DateTime.UtcNow; + } + + // 领域接口 + public interface IDeviceService + { + Task GetSerialNumberAsync(); + DeviceInfo GetSerialNumber(); + } + + // 基础设施实现 + public class DeviceService : IDeviceService + { + private readonly ISystemCommandExecutor _commandExecutor; + + public async Task GetSerialNumberAsync() + { + string command = GetSerialNumberCommand(); + var result = await _commandExecutor.ExecuteCommandAsync(command, new CancellationTokenSource(), 5000); + return ParseSerialNumber(result.Output); + } + } + + // 应用层处理器 + public async Task> Handle(GetSerialNumberCommand request, CancellationToken cancellationToken) + { + var deviceInfo = await _deviceService.GetSerialNumberAsync(); + return ApiActionResult.Ok(deviceInfo, "获取设备序列号成功"); + } + + // API控制器 + [HttpGet("serial-number")] + public async Task GetSerialNumber() + { + var command = new GetSerialNumberCommand(); + var result = await _mediator.Send(command); + return result; + } + ``` + +7. **设计优势**: + - **DDD架构**: 严格遵循领域驱动设计的分层架构 + - **依赖倒置**: 高层模块依赖抽象,不依赖具体实现 + - **单一职责**: 每个类都有明确的职责 + - **跨平台支持**: 自动识别操作系统并使用对应命令 + - **错误处理**: 完善的异常处理和日志记录 + - **可测试性**: 接口抽象便于单元测试 + - **可扩展性**: 易于添加新的设备信息获取功能 + +**影响范围**: +- 新增系统服务模块 +- 扩展API接口 +- 依赖注入配置更新 +- 命令处理流程扩展 + ### 创建MessageTransferProtocolLog模型解决命名冲突 **修改时间**: 2024年 @@ -746,4 +849,115 @@ - 依赖注入容器的服务解析 - 应用程序启动时的服务注册 - 中间件的实例化策略 -- 性能和内存使用优化 \ No newline at end of file +- 性能和内存使用优化 + +### DeviceInfo模型添加IsSuccess字段和ParseSerialNumber方法优化 + +**修改时间**: 2024年 +**修改文件**: +- `CoreAgent.Domain/Models/System/DeviceInfo.cs` +- `CoreAgent.Infrastructure/Services/System/DeviceService.cs` +- `CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs` + +**修改内容**: + +1. **DeviceInfo模型添加IsSuccess字段** + - 添加 `bool IsSuccess { get; set; }` 属性 + - 用于标识是否成功获取到序列号 + - 提供更准确的成功/失败状态判断 + +2. **ParseSerialNumber方法优化** + - 返回类型从 `string` 改为 `string?`(可空字符串) + - 失败时返回 `null` 而不是固定字符串 + - 修复Linux系统输出格式解析:`Serial Number: xxxxxxxx` + - 添加更详细的注释说明返回值含义 + +3. **DeviceService方法更新** + - 修改异步和同步方法中的DeviceInfo创建逻辑 + - 根据ParseSerialNumber返回值设置IsSuccess字段 + - 成功时设置 `IsSuccess = true` + - 失败时设置 `IsSuccess = false` + - 添加更详细的日志记录 + +4. **GetSerialNumberCommandHandler优化** + - 在Handle方法中检查 `deviceInfo.IsSuccess` 字段 + - 成功时返回 `ApiActionResult.Ok()` + - 失败时返回 `ApiActionResult.Error()` 并设置错误代码 `DEVICE_SN_NOT_FOUND` + - 提供更准确的错误信息 + +5. **具体实现**: + ```csharp + // DeviceInfo模型 + public class DeviceInfo + { + public bool IsSuccess { get; set; } + public string SerialNumber { get; set; } = string.Empty; + public DateTime Timestamp { get; set; } = DateTime.UtcNow; + } + + // ParseSerialNumber方法 + private string? ParseSerialNumber(string output) + { + if (string.IsNullOrWhiteSpace(output)) + return null; + + 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; + } + + // DeviceService中的使用 + if (serialNumber != null) + { + return new DeviceInfo + { + IsSuccess = true, + SerialNumber = serialNumber, + Timestamp = DateTime.UtcNow + }; + } + else + { + return new DeviceInfo + { + IsSuccess = false, + SerialNumber = "UNKNOWN", + Timestamp = DateTime.UtcNow + }; + } + + // GetSerialNumberCommandHandler中的使用 + if (deviceInfo.IsSuccess) + { + return ApiActionResult.Ok(deviceInfo, "获取设备序列号成功"); + } + else + { + return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND"); + } + ``` + +6. **设计优势**: + - **准确的状态判断**:通过IsSuccess字段明确标识操作结果 + - **更好的错误处理**:区分不同类型的失败情况 + - **Linux兼容性**:正确解析Linux系统的序列号输出格式 + - **空值安全**:使用可空字符串避免固定错误字符串 + - **详细日志**:提供更丰富的日志信息便于调试 + - **API一致性**:返回统一的ApiActionResult格式 + +**影响范围**: +- 设备序列号获取的准确性 +- API响应的错误处理 +- Linux系统兼容性 +- 日志记录的详细程度 +- 客户端错误处理逻辑 \ No newline at end of file From 6aadfe9de5b38a6e8bb5fe0c14746b86aea9c954 Mon Sep 17 00:00:00 2001 From: hyh Date: Tue, 29 Jul 2025 15:02:48 +0800 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=E5=88=9B=E5=BB=BADeviceInfoRes?= =?UTF-8?q?ponse=E6=A8=A1=E5=9E=8B=EF=BC=8C=E4=BC=98=E5=8C=96API=E5=93=8D?= =?UTF-8?q?=E5=BA=94=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增DeviceInfoResponse模型,专门用于API响应 - 移除API响应中的IsSuccess字段,确保响应简洁 - 修改GetSerialNumberCommand返回类型为ApiActionResult - 更新GetSerialNumberCommandHandler使用DeviceInfoResponse - 实现清晰的职责分离:DeviceInfo用于内部状态判断,DeviceInfoResponse用于API响应 - 确保API响应不包含内部实现细节 --- .../Commands/System/GetSerialNumberCommand.cs | 2 +- .../System/GetSerialNumberCommandHandler.cs | 18 +++++++--- .../Models/System/DeviceInfoResponse.cs | 17 +++++++++ modify.md | 35 +++++++++++++++---- 4 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 CoreAgent.Domain/Models/System/DeviceInfoResponse.cs diff --git a/CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs b/CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs index 932e356..e8635eb 100644 --- a/CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs +++ b/CoreAgent.Application/Commands/System/GetSerialNumberCommand.cs @@ -7,7 +7,7 @@ namespace CoreAgent.Application.Commands.System; /// /// 获取设备序列号命令 /// -public class GetSerialNumberCommand : IRequest> +public class GetSerialNumberCommand : IRequest> { // 命令不需要额外参数,直接获取当前设备的序列号 } \ No newline at end of file diff --git a/CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs b/CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs index 249c697..eda26db 100644 --- a/CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs +++ b/CoreAgent.Application/Handlers/System/GetSerialNumberCommandHandler.cs @@ -10,7 +10,7 @@ namespace CoreAgent.Application.Handlers.System; /// /// 获取设备序列号命令处理器 /// -public class GetSerialNumberCommandHandler : IRequestHandler> +public class GetSerialNumberCommandHandler : IRequestHandler> { private readonly IDeviceService _deviceService; private readonly ILogger _logger; @@ -23,7 +23,7 @@ public class GetSerialNumberCommandHandler : IRequestHandler> Handle(GetSerialNumberCommand request, CancellationToken cancellationToken) + public async Task> Handle(GetSerialNumberCommand request, CancellationToken cancellationToken) { try { @@ -34,18 +34,26 @@ public class GetSerialNumberCommandHandler : IRequestHandler.Ok(deviceInfo, "获取设备序列号成功"); + + // 创建DeviceInfoResponse对象,不包含IsSuccess字段 + var resultDeviceInfo = new DeviceInfoResponse + { + SerialNumber = deviceInfo.SerialNumber, + Timestamp = deviceInfo.Timestamp + }; + + return ApiActionResult.Ok(resultDeviceInfo, "获取设备序列号成功"); } else { _logger.LogWarning("获取设备序列号失败,返回的序列号: {SerialNumber}", deviceInfo.SerialNumber); - return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND"); + return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND"); } } catch (Exception ex) { _logger.LogError(ex, "处理获取设备序列号命令时发生异常"); - return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_ERROR"); + return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_ERROR"); } } } \ No newline at end of file diff --git a/CoreAgent.Domain/Models/System/DeviceInfoResponse.cs b/CoreAgent.Domain/Models/System/DeviceInfoResponse.cs new file mode 100644 index 0000000..d936a8a --- /dev/null +++ b/CoreAgent.Domain/Models/System/DeviceInfoResponse.cs @@ -0,0 +1,17 @@ +namespace CoreAgent.Domain.Models.System; + +/// +/// 设备信息响应模型(用于API响应) +/// +public class DeviceInfoResponse +{ + /// + /// 设备序列号(SN) + /// + public string SerialNumber { get; set; } = string.Empty; + + /// + /// 获取时间 + /// + public DateTime Timestamp { get; set; } = DateTime.UtcNow; +} \ No newline at end of file diff --git a/modify.md b/modify.md index a54ea75..cc0801e 100644 --- a/modify.md +++ b/modify.md @@ -856,7 +856,9 @@ **修改时间**: 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` **修改内容**: @@ -866,6 +868,12 @@ - 用于标识是否成功获取到序列号 - 提供更准确的成功/失败状态判断 +2. **创建DeviceInfoResponse模型** + - 创建专门用于API响应的模型 + - 只包含 `SerialNumber` 和 `Timestamp` 字段 + - 不包含内部状态字段 `IsSuccess` + - 确保API响应简洁明了 + 2. **ParseSerialNumber方法优化** - 返回类型从 `string` 改为 `string?`(可空字符串) - 失败时返回 `null` 而不是固定字符串 @@ -879,15 +887,17 @@ - 失败时设置 `IsSuccess = false` - 添加更详细的日志记录 -4. **GetSerialNumberCommandHandler优化** +4. **GetSerialNumberCommand和GetSerialNumberCommandHandler优化** + - 修改命令返回类型为 `ApiActionResult` - 在Handle方法中检查 `deviceInfo.IsSuccess` 字段 - - 成功时返回 `ApiActionResult.Ok()` - - 失败时返回 `ApiActionResult.Error()` 并设置错误代码 `DEVICE_SN_NOT_FOUND` + - 成功时创建 `DeviceInfoResponse` 对象返回,不包含IsSuccess字段 + - 失败时返回 `ApiActionResult.Error()` 并设置错误代码 `DEVICE_SN_NOT_FOUND` - 提供更准确的错误信息 + - 确保API返回的响应模型不包含内部状态字段 5. **具体实现**: ```csharp - // DeviceInfo模型 + // DeviceInfo模型(内部使用) public class DeviceInfo { public bool IsSuccess { get; set; } @@ -895,6 +905,13 @@ public DateTime Timestamp { get; set; } = DateTime.UtcNow; } + // DeviceInfoResponse模型(API响应) + public class DeviceInfoResponse + { + public string SerialNumber { get; set; } = string.Empty; + public DateTime Timestamp { get; set; } = DateTime.UtcNow; + } + // ParseSerialNumber方法 private string? ParseSerialNumber(string output) { @@ -939,11 +956,17 @@ // GetSerialNumberCommandHandler中的使用 if (deviceInfo.IsSuccess) { - return ApiActionResult.Ok(deviceInfo, "获取设备序列号成功"); + // 创建DeviceInfoResponse对象,不包含IsSuccess字段 + var resultDeviceInfo = new DeviceInfoResponse + { + SerialNumber = deviceInfo.SerialNumber, + Timestamp = deviceInfo.Timestamp + }; + return ApiActionResult.Ok(resultDeviceInfo, "获取设备序列号成功"); } else { - return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND"); + return ApiActionResult.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND"); } ```