You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
12 KiB
317 lines
12 KiB
using MediatR;
|
|
using Microsoft.Extensions.Logging;
|
|
using CellularManagement.Domain.Common;
|
|
using CellularManagement.Domain.Entities.Device;
|
|
using CellularManagement.Domain.Repositories;
|
|
using CellularManagement.Domain.Repositories.Device;
|
|
using CellularManagement.Domain.Repositories.Base;
|
|
using CellularManagement.Domain.Services;
|
|
using X1.DynamicClientCore.Features;
|
|
using X1.DynamicClientCore.Models;
|
|
using X1.DynamicClientCore.Interfaces;
|
|
|
|
namespace CellularManagement.Application.Features.Devices.Commands.CreateDevice;
|
|
|
|
/// <summary>
|
|
/// 创建设备命令处理器
|
|
/// </summary>
|
|
public class CreateDeviceCommandHandler : IRequestHandler<CreateDeviceCommand, OperationResult<CreateDeviceResponse>>
|
|
{
|
|
private readonly ICellularDeviceRepository _deviceRepository;
|
|
private readonly ILogger<CreateDeviceCommandHandler> _logger;
|
|
private readonly IUnitOfWork _unitOfWork;
|
|
private readonly ICurrentUserService _currentUserService;
|
|
private readonly IBaseInstrumentClient _instrumentClient;
|
|
private readonly IServiceEndpointManager _endpointManager;
|
|
|
|
/// <summary>
|
|
/// 初始化命令处理器
|
|
/// </summary>
|
|
public CreateDeviceCommandHandler(
|
|
ICellularDeviceRepository deviceRepository,
|
|
ILogger<CreateDeviceCommandHandler> logger,
|
|
IUnitOfWork unitOfWork,
|
|
ICurrentUserService currentUserService,
|
|
IBaseInstrumentClient instrumentClient,
|
|
IServiceEndpointManager endpointManager)
|
|
{
|
|
_deviceRepository = deviceRepository;
|
|
_logger = logger;
|
|
_unitOfWork = unitOfWork;
|
|
_currentUserService = currentUserService;
|
|
_instrumentClient = instrumentClient;
|
|
_endpointManager = endpointManager;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 处理创建设备命令
|
|
/// </summary>
|
|
public async Task<OperationResult<CreateDeviceResponse>> Handle(CreateDeviceCommand request, CancellationToken cancellationToken)
|
|
{
|
|
// 验证请求参数
|
|
var validationResult = ValidateRequest(request);
|
|
if (!validationResult.IsSuccess)
|
|
{
|
|
return OperationResult<CreateDeviceResponse>.CreateFailure(validationResult.ErrorMessages);
|
|
}
|
|
|
|
_logger.LogInformation("开始创建设备,设备名称: {DeviceName}, IP地址: {IpAddress}",
|
|
request.DeviceName, request.IpAddress);
|
|
|
|
// 验证用户认证
|
|
var currentUserId = ValidateUserAuthentication();
|
|
if (!currentUserId.IsSuccess)
|
|
{
|
|
return OperationResult<CreateDeviceResponse>.CreateFailure(currentUserId.ErrorMessages);
|
|
}
|
|
|
|
// 创建服务端点
|
|
var serviceEndpoint = CreateServiceEndpoint(request);
|
|
|
|
// 获取设备序列号
|
|
var serialNumberResult = await GetDeviceSerialNumberAsync(request, serviceEndpoint, cancellationToken);
|
|
if (!serialNumberResult.IsSuccess)
|
|
{
|
|
return OperationResult<CreateDeviceResponse>.CreateFailure(serialNumberResult.ErrorMessages);
|
|
}
|
|
|
|
var serialNumber = serialNumberResult.Data;
|
|
|
|
// 验证序列号
|
|
if (string.IsNullOrWhiteSpace(serialNumber))
|
|
{
|
|
_logger.LogError("获取到的序列号为空");
|
|
return OperationResult<CreateDeviceResponse>.CreateFailure("无法获取设备序列号");
|
|
}
|
|
|
|
// 检查序列号是否已存在
|
|
if (await _deviceRepository.SerialNumberExistsAsync(serialNumber, cancellationToken))
|
|
{
|
|
_logger.LogWarning("设备序列号已存在: {SerialNumber}", serialNumber);
|
|
return OperationResult<CreateDeviceResponse>.CreateFailure($"设备序列号 {serialNumber} 已存在");
|
|
}
|
|
|
|
// 生成设备编号
|
|
var deviceCode = await GenerateDeviceCodeAsync(serialNumber, cancellationToken);
|
|
|
|
// 验证设备编号
|
|
if (string.IsNullOrWhiteSpace(deviceCode))
|
|
{
|
|
_logger.LogError("生成的设备编号为空");
|
|
return OperationResult<CreateDeviceResponse>.CreateFailure("生成设备编号失败");
|
|
}
|
|
|
|
// 创建设备并保存
|
|
var deviceResult = await CreateAndSaveDeviceAsync(request, serialNumber, deviceCode, currentUserId.Data, cancellationToken);
|
|
if (!deviceResult.IsSuccess)
|
|
{
|
|
return OperationResult<CreateDeviceResponse>.CreateFailure(deviceResult.ErrorMessages);
|
|
}
|
|
|
|
var device = deviceResult.Data;
|
|
|
|
// 设备保存成功后,修改端点名称并重新添加
|
|
serviceEndpoint.Name = deviceCode;
|
|
_endpointManager.AddOrUpdateEndpoint(serviceEndpoint);
|
|
_logger.LogDebug("设备保存成功后,已添加服务端点: {EndpointName}", deviceCode);
|
|
|
|
// 构建响应
|
|
var response = new CreateDeviceResponse
|
|
{
|
|
DeviceId = device.Id,
|
|
DeviceName = device.Name,
|
|
SerialNumber = device.SerialNumber,
|
|
DeviceCode = device.DeviceCode,
|
|
Description = device.Description,
|
|
AgentPort = device.AgentPort,
|
|
IsEnabled = device.IsEnabled,
|
|
IsRunning = device.IsRunning,
|
|
CreatedAt = device.CreatedAt
|
|
};
|
|
|
|
_logger.LogInformation("设备创建成功,设备ID: {DeviceId}, 设备名称: {DeviceName}, 序列号: {SerialNumber}",
|
|
device.Id, device.Name, device.SerialNumber);
|
|
|
|
return OperationResult<CreateDeviceResponse>.CreateSuccess(response);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 验证请求参数
|
|
/// </summary>
|
|
private OperationResult<bool> ValidateRequest(CreateDeviceCommand request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
_logger.LogError("请求参数为空");
|
|
return OperationResult<bool>.CreateFailure("请求参数不能为空");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(request.DeviceName))
|
|
{
|
|
_logger.LogError("设备名称为空");
|
|
return OperationResult<bool>.CreateFailure("设备名称不能为空");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(request.IpAddress))
|
|
{
|
|
_logger.LogError("IP地址为空");
|
|
return OperationResult<bool>.CreateFailure("IP地址不能为空");
|
|
}
|
|
|
|
if (request.AgentPort <= 0 || request.AgentPort > 65535)
|
|
{
|
|
_logger.LogError("Agent端口无效: {AgentPort}", request.AgentPort);
|
|
return OperationResult<bool>.CreateFailure("Agent端口必须在1-65535之间");
|
|
}
|
|
|
|
return OperationResult<bool>.CreateSuccess(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 验证用户认证
|
|
/// </summary>
|
|
private OperationResult<string> ValidateUserAuthentication()
|
|
{
|
|
var currentUserId = _currentUserService.GetCurrentUserId();
|
|
if (string.IsNullOrEmpty(currentUserId))
|
|
{
|
|
_logger.LogError("无法获取当前用户ID,用户可能未认证");
|
|
return OperationResult<string>.CreateFailure("用户未认证,无法创建设备");
|
|
}
|
|
return OperationResult<string>.CreateSuccess(currentUserId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取设备序列号
|
|
/// </summary>
|
|
private async Task<OperationResult<string>> GetDeviceSerialNumberAsync(CreateDeviceCommand request, ServiceEndpoint serviceEndpoint, CancellationToken cancellationToken)
|
|
{
|
|
|
|
try
|
|
{
|
|
// 添加服务端点到管理器
|
|
_endpointManager.AddOrUpdateEndpoint(serviceEndpoint);
|
|
_logger.LogDebug("已添加服务端点: {EndpointName}", serviceEndpoint.Name);
|
|
|
|
// 获取设备序列号
|
|
var serialNumber = await _instrumentClient.GetDeviceSerialNumberAsync(serviceEndpoint.Name, null, cancellationToken);
|
|
|
|
if (string.IsNullOrEmpty(serialNumber))
|
|
{
|
|
_logger.LogWarning("无法通过IP地址获取设备序列号,IP地址: {IpAddress}", request.IpAddress);
|
|
// 获取序列号失败时清理服务端点
|
|
_endpointManager.RemoveEndpoint(serviceEndpoint.Name);
|
|
_logger.LogDebug("已清理服务端点: {EndpointName}", serviceEndpoint.Name);
|
|
return OperationResult<string>.CreateFailure($"无法通过IP地址 {request.IpAddress} 获取设备序列号,请检查设备连接状态");
|
|
}
|
|
|
|
_logger.LogInformation("成功获取设备序列号: {SerialNumber}, IP地址: {IpAddress}", serialNumber, request.IpAddress);
|
|
|
|
// 获取序列号成功后,移除临时服务端点
|
|
_endpointManager.RemoveEndpoint(serviceEndpoint.Name);
|
|
_logger.LogDebug("已移除临时服务端点: {EndpointName}", serviceEndpoint.Name);
|
|
|
|
return OperationResult<string>.CreateSuccess(serialNumber);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取设备序列号时发生异常,IP地址: {IpAddress}", request.IpAddress);
|
|
// 发生异常时清理服务端点
|
|
_endpointManager.RemoveEndpoint(serviceEndpoint.Name);
|
|
_logger.LogDebug("已清理服务端点: {EndpointName}", serviceEndpoint.Name);
|
|
return OperationResult<string>.CreateFailure($"获取设备序列号时发生错误: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成设备编号
|
|
/// </summary>
|
|
private async Task<string> GenerateDeviceCodeAsync(string serialNumber, CancellationToken cancellationToken)
|
|
{
|
|
// 获取当前设备总数
|
|
var deviceCount = await _deviceRepository.GetDeviceCountAsync(cancellationToken);
|
|
var nextNumber = deviceCount + 1;
|
|
|
|
// 计算需要的位数,确保至少3位数
|
|
var digitCount = CalculateRequiredDigits(nextNumber);
|
|
|
|
// 格式化序号,动态补0,确保从000开始
|
|
var formattedNumber = nextNumber.ToString($"D{digitCount}");
|
|
|
|
// 生成设备编号格式:DEV-000-SN, DEV-001-SN, DEV-002-SN 等
|
|
var deviceCode = $"DEV-{formattedNumber}-{serialNumber}";
|
|
|
|
_logger.LogDebug("生成设备编号: {DeviceCode}, 设备总数: {DeviceCount}, 位数: {DigitCount}", deviceCode, deviceCount, digitCount);
|
|
|
|
return deviceCode;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算需要的位数
|
|
/// </summary>
|
|
private int CalculateRequiredDigits(int number)
|
|
{
|
|
if (number <= 0) return 3; // 从000开始,至少3位数
|
|
|
|
// 计算位数:确保至少3位数,从000开始
|
|
// 1-999用3位,1000-9999用4位,10000-99999用5位,以此类推
|
|
var calculatedDigits = (int)Math.Floor(Math.Log10(number)) + 1;
|
|
return Math.Max(calculatedDigits, 3); // 确保至少3位数
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建服务端点配置
|
|
/// </summary>
|
|
private ServiceEndpoint CreateServiceEndpoint(CreateDeviceCommand request)
|
|
{
|
|
return new ServiceEndpoint
|
|
{
|
|
Name = $"DEV-{Guid.NewGuid():N}",
|
|
Ip = request.IpAddress,
|
|
Port = request.AgentPort,
|
|
Protocol = "http",
|
|
BasePath= "/api/v1",
|
|
Timeout = 10,
|
|
Enabled = true
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建设备并保存到数据库
|
|
/// </summary>
|
|
private async Task<OperationResult<CellularDevice>> CreateAndSaveDeviceAsync(
|
|
CreateDeviceCommand request,
|
|
string serialNumber,
|
|
string deviceCode,
|
|
string currentUserId,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
// 创建设备实体
|
|
var device = CellularDevice.Create(
|
|
name: request.DeviceName,
|
|
serialNumber: serialNumber,
|
|
deviceCode: deviceCode,
|
|
description: request.Description,
|
|
agentPort: request.AgentPort,
|
|
ipAddress: request.IpAddress,
|
|
createdBy: currentUserId,
|
|
isEnabled: request.IsEnabled,
|
|
isRunning: request.IsRunning);
|
|
|
|
// 保存设备
|
|
await _deviceRepository.AddDeviceAsync(device, cancellationToken);
|
|
|
|
// 保存更改到数据库
|
|
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
|
|
|
return OperationResult<CellularDevice>.CreateSuccess(device);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "创建设备实体时发生错误,设备名称: {DeviceName}", request.DeviceName);
|
|
return OperationResult<CellularDevice>.CreateFailure($"创建设备时发生错误: {ex.Message}");
|
|
}
|
|
}
|
|
}
|