Browse Source
- 新增DeviceInfo模型,包含IsSuccess字段用于状态判断 - 实现IDeviceService接口和DeviceService实现类 - 支持Windows和Linux系统序列号获取 - 修复ParseSerialNumber方法,支持Linux输出格式解析 - 创建GetSerialNumberCommand和GetSerialNumberCommandHandler - 添加SystemController API控制器 - 修复CS0234编译错误,添加System.Net引用 - 更新依赖注入配置 - 完善错误处理和日志记录feature/protocol-log-Perfect
16 changed files with 597 additions and 14 deletions
@ -0,0 +1,34 @@ |
|||||
|
using CoreAgent.Application.Commands.System; |
||||
|
using CoreAgent.Domain.Models.System; |
||||
|
using MediatR; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace CoreAgent.API.Controllers; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 系统控制器
|
||||
|
/// </summary>
|
||||
|
public class SystemController : BaseApiController |
||||
|
{ |
||||
|
public SystemController(IMediator mediator, ILogger<SystemController> logger) |
||||
|
: base(mediator, logger) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取设备序列号(SN)
|
||||
|
/// </summary>
|
||||
|
/// <returns>设备信息</returns>
|
||||
|
[HttpGet("serial-number")] |
||||
|
public async Task<IActionResult> GetSerialNumber() |
||||
|
{ |
||||
|
_logger.LogInformation("收到获取设备序列号请求"); |
||||
|
|
||||
|
var command = new GetSerialNumberCommand(); |
||||
|
var result = await _mediator.Send(command); |
||||
|
|
||||
|
_logger.LogInformation("成功返回设备序列号: {SerialNumber}", result.Data?.SerialNumber); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
using CoreAgent.Domain.Models.Common; |
||||
|
using CoreAgent.Domain.Models.System; |
||||
|
using MediatR; |
||||
|
|
||||
|
namespace CoreAgent.Application.Commands.System; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取设备序列号命令
|
||||
|
/// </summary>
|
||||
|
public class GetSerialNumberCommand : IRequest<ApiActionResult<DeviceInfo>> |
||||
|
{ |
||||
|
// 命令不需要额外参数,直接获取当前设备的序列号
|
||||
|
} |
@ -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; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取设备序列号命令处理器
|
||||
|
/// </summary>
|
||||
|
public class GetSerialNumberCommandHandler : IRequestHandler<GetSerialNumberCommand, ApiActionResult<DeviceInfo>> |
||||
|
{ |
||||
|
private readonly IDeviceService _deviceService; |
||||
|
private readonly ILogger<GetSerialNumberCommandHandler> _logger; |
||||
|
|
||||
|
public GetSerialNumberCommandHandler( |
||||
|
IDeviceService deviceService, |
||||
|
ILogger<GetSerialNumberCommandHandler> logger) |
||||
|
{ |
||||
|
_deviceService = deviceService ?? throw new ArgumentNullException(nameof(deviceService)); |
||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); |
||||
|
} |
||||
|
|
||||
|
public async Task<ApiActionResult<DeviceInfo>> Handle(GetSerialNumberCommand request, CancellationToken cancellationToken) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
_logger.LogInformation("开始处理获取设备序列号命令"); |
||||
|
|
||||
|
var deviceInfo = await _deviceService.GetSerialNumberAsync(); |
||||
|
|
||||
|
if (deviceInfo.IsSuccess) |
||||
|
{ |
||||
|
_logger.LogInformation("成功获取设备序列号: {SerialNumber}", deviceInfo.SerialNumber); |
||||
|
return ApiActionResult<DeviceInfo>.Ok(deviceInfo, "获取设备序列号成功"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_logger.LogWarning("获取设备序列号失败,返回的序列号: {SerialNumber}", deviceInfo.SerialNumber); |
||||
|
return ApiActionResult<DeviceInfo>.Error("获取设备序列号失败", "DEVICE_SN_NOT_FOUND"); |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_logger.LogError(ex, "处理获取设备序列号命令时发生异常"); |
||||
|
return ApiActionResult<DeviceInfo>.Error("获取设备序列号失败", "DEVICE_SN_ERROR"); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
using CoreAgent.Domain.Models.System; |
||||
|
|
||||
|
namespace CoreAgent.Domain.Interfaces.System; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设备服务接口
|
||||
|
/// </summary>
|
||||
|
public interface IDeviceService |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 获取设备序列号(SN)
|
||||
|
/// </summary>
|
||||
|
/// <returns>设备信息</returns>
|
||||
|
Task<DeviceInfo> GetSerialNumberAsync(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取设备序列号(SN)- 同步版本
|
||||
|
/// </summary>
|
||||
|
/// <returns>设备信息</returns>
|
||||
|
DeviceInfo GetSerialNumber(); |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
namespace CoreAgent.Domain.Models.System; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设备信息模型
|
||||
|
/// </summary>
|
||||
|
public class DeviceInfo |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 是否成功获取到序列号
|
||||
|
/// </summary>
|
||||
|
public bool IsSuccess { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设备序列号(SN)
|
||||
|
/// </summary>
|
||||
|
public string SerialNumber { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取时间
|
||||
|
/// </summary>
|
||||
|
public DateTime Timestamp { get; set; } = DateTime.UtcNow; |
||||
|
} |
@ -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; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 设备服务实现
|
||||
|
/// </summary>
|
||||
|
public class DeviceService : IDeviceService |
||||
|
{ |
||||
|
private readonly ILogger<DeviceService> _logger; |
||||
|
private readonly ISystemCommandExecutor _commandExecutor; |
||||
|
|
||||
|
public DeviceService( |
||||
|
ILogger<DeviceService> logger, |
||||
|
ISystemCommandExecutor commandExecutor) |
||||
|
{ |
||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); |
||||
|
_commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取设备序列号(SN)
|
||||
|
/// </summary>
|
||||
|
/// <returns>设备信息</returns>
|
||||
|
public async Task<DeviceInfo> 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 |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取设备序列号(SN)- 同步版本
|
||||
|
/// </summary>
|
||||
|
/// <returns>设备信息</returns>
|
||||
|
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 |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 根据操作系统获取序列号命令
|
||||
|
/// </summary>
|
||||
|
/// <returns>命令字符串</returns>
|
||||
|
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"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 解析序列号输出
|
||||
|
/// </summary>
|
||||
|
/// <param name="output">命令输出</param>
|
||||
|
/// <returns>解析后的序列号,失败时返回null</returns>
|
||||
|
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; |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue