using System.Diagnostics; using Aging.Infrastructure.Contracts; using log4net; namespace Aging.Infrastructure.Services { /// /// 设备服务实现。 /// 协调 ResourceManager、DeviceManager 和 SlotMapping, /// 提供面向 DeviceId 的命令执行、查询和安全关机功能。 /// 所有操作均需通过资源预约验证和租约管理,确保硬件资源的安全访问。 /// public sealed class DeviceService : IDeviceService { private static readonly ILog Log = LogManager.GetLogger(typeof(DeviceService)); /// /// 资源管理器 /// private readonly IResourceManager _resourceManager; /// /// 设备管理器 /// private readonly IDeviceManager _deviceManager; /// /// Slot-设备-通道映射解析器 /// private readonly SlotDeviceMappingResolver _slotMappingResolver; /// /// 初始化设备服务实例 /// /// 资源管理器 /// 设备管理器 /// Slot 映射解析器 public DeviceService( IResourceManager resourceManager, IDeviceManager deviceManager, SlotDeviceMappingResolver slotMappingResolver) { _resourceManager = resourceManager ?? throw new ArgumentNullException(nameof(resourceManager)); _deviceManager = deviceManager ?? throw new ArgumentNullException(nameof(deviceManager)); _slotMappingResolver = slotMappingResolver ?? throw new ArgumentNullException(nameof(slotMappingResolver)); } /// public async Task ExecuteCommandAsync( string deviceId, string command, ResourceOwnerToken owner, CancellationToken ct) { if (string.IsNullOrWhiteSpace(deviceId)) throw new ArgumentException("设备ID不能为空", nameof(deviceId)); if (string.IsNullOrWhiteSpace(command)) throw new ArgumentException("命令不能为空", nameof(command)); if (owner == null) throw new ArgumentNullException(nameof(owner)); var stopwatch = Stopwatch.StartNew(); var resourceKey = new ResourceKey(deviceId, "Generic"); try { Log.Info($"[DeviceService] 执行命令: Device={deviceId}, Command={command}, Owner={owner.OwnerId}"); // 1. 获取设备驱动 var driver = _deviceManager.GetDriver(deviceId); if (driver == null) { stopwatch.Stop(); Log.Warn($"[DeviceService] 设备 {deviceId} 驱动不存在"); return new DeviceCommandResult { Success = false, ErrorCode = "DRIVER_NOT_FOUND", ErrorMessage = $"设备 {deviceId} 的驱动未注册", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } // 2. 验证预约 if (!_resourceManager.ValidateOwner(owner, resourceKey)) { stopwatch.Stop(); Log.Warn($"[DeviceService] 权限验证失败: Device={deviceId}, Owner={owner.OwnerId}"); return new DeviceCommandResult { Success = false, ErrorCode = "PERMISSION_DENIED", ErrorMessage = $"所有者 {owner.OwnerId} 未预约设备 {deviceId} 或令牌已过期", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } // 3. 获取租约并执行命令 using var lease = await _resourceManager.AcquireOperationAsync(owner, resourceKey, ct).ConfigureAwait(false); var response = await driver.SendCommandAsync(command, ct).ConfigureAwait(false); stopwatch.Stop(); Log.Info($"[DeviceService] 命令执行成功: Device={deviceId}, Command={command}, 延迟={stopwatch.Elapsed.TotalMilliseconds:F2}ms"); return new DeviceCommandResult { Success = true, RawResponse = response, Readback = response, LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (ResourceConflictException ex) { stopwatch.Stop(); Log.Error($"[DeviceService] 资源冲突: Device={deviceId}, 错误: {ex.Message}", ex); return new DeviceCommandResult { Success = false, ErrorCode = "RESOURCE_CONFLICT", ErrorMessage = ex.Message, LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (OperationCanceledException) { stopwatch.Stop(); Log.Warn($"[DeviceService] 命令执行被取消: Device={deviceId}"); return new DeviceCommandResult { Success = false, ErrorCode = "OPERATION_CANCELLED", ErrorMessage = "操作已被取消", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (TimeoutException ex) { stopwatch.Stop(); Log.Error($"[DeviceService] 命令执行超时: Device={deviceId}, 错误: {ex.Message}", ex); return new DeviceCommandResult { Success = false, ErrorCode = "TIMEOUT", ErrorMessage = $"设备 {deviceId} 命令执行超时: {ex.Message}", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (Exception ex) { stopwatch.Stop(); Log.Error($"[DeviceService] 命令执行异常: Device={deviceId}, 错误: {ex.Message}", ex); return new DeviceCommandResult { Success = false, ErrorCode = "UNKNOWN_ERROR", ErrorMessage = $"设备 {deviceId} 命令执行失败: {ex.Message}", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } } /// public async Task ExecuteQueryAsync( string deviceId, string query, ResourceOwnerToken owner, CancellationToken ct) { if (string.IsNullOrWhiteSpace(deviceId)) throw new ArgumentException("设备ID不能为空", nameof(deviceId)); if (string.IsNullOrWhiteSpace(query)) throw new ArgumentException("查询命令不能为空", nameof(query)); if (owner == null) throw new ArgumentNullException(nameof(owner)); var stopwatch = Stopwatch.StartNew(); var resourceKey = new ResourceKey(deviceId, "Generic"); try { Log.Info($"[DeviceService] 执行查询: Device={deviceId}, Query={query}, Owner={owner.OwnerId}"); // 1. 获取设备驱动 var driver = _deviceManager.GetDriver(deviceId); if (driver == null) { stopwatch.Stop(); Log.Warn($"[DeviceService] 设备 {deviceId} 驱动不存在"); return new DeviceCommandResult { Success = false, ErrorCode = "DRIVER_NOT_FOUND", ErrorMessage = $"设备 {deviceId} 的驱动未注册", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } // 2. 验证预约 if (!_resourceManager.ValidateOwner(owner, resourceKey)) { stopwatch.Stop(); Log.Warn($"[DeviceService] 权限验证失败: Device={deviceId}, Owner={owner.OwnerId}"); return new DeviceCommandResult { Success = false, ErrorCode = "PERMISSION_DENIED", ErrorMessage = $"所有者 {owner.OwnerId} 未预约设备 {deviceId} 或令牌已过期", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } // 3. 获取租约并执行查询 using var lease = await _resourceManager.AcquireOperationAsync(owner, resourceKey, ct).ConfigureAwait(false); var response = await driver.QueryAsync(query, ct).ConfigureAwait(false); stopwatch.Stop(); Log.Info($"[DeviceService] 查询执行成功: Device={deviceId}, Query={query}, 延迟={stopwatch.Elapsed.TotalMilliseconds:F2}ms"); return new DeviceCommandResult { Success = true, RawResponse = response, Readback = response, LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (ResourceConflictException ex) { stopwatch.Stop(); Log.Error($"[DeviceService] 资源冲突: Device={deviceId}, 错误: {ex.Message}", ex); return new DeviceCommandResult { Success = false, ErrorCode = "RESOURCE_CONFLICT", ErrorMessage = ex.Message, LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (OperationCanceledException) { stopwatch.Stop(); Log.Warn($"[DeviceService] 查询执行被取消: Device={deviceId}"); return new DeviceCommandResult { Success = false, ErrorCode = "OPERATION_CANCELLED", ErrorMessage = "操作已被取消", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (TimeoutException ex) { stopwatch.Stop(); Log.Error($"[DeviceService] 查询执行超时: Device={deviceId}, 错误: {ex.Message}", ex); return new DeviceCommandResult { Success = false, ErrorCode = "TIMEOUT", ErrorMessage = $"设备 {deviceId} 查询执行超时: {ex.Message}", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } catch (Exception ex) { stopwatch.Stop(); Log.Error($"[DeviceService] 查询执行异常: Device={deviceId}, 错误: {ex.Message}", ex); return new DeviceCommandResult { Success = false, ErrorCode = "UNKNOWN_ERROR", ErrorMessage = $"设备 {deviceId} 查询执行失败: {ex.Message}", LatencyMs = stopwatch.Elapsed.TotalMilliseconds }; } } /// public async Task SafeShutdownAsync(string deviceId, ResourceOwnerToken owner, CancellationToken ct) { if (string.IsNullOrWhiteSpace(deviceId)) throw new ArgumentException("设备ID不能为空", nameof(deviceId)); if (owner == null) throw new ArgumentNullException(nameof(owner)); var resourceKey = new ResourceKey(deviceId, "Generic"); try { Log.Info($"[DeviceService] 开始安全关机: Device={deviceId}, Owner={owner.OwnerId}"); // 1. 获取驱动 var driver = _deviceManager.GetDriver(deviceId); if (driver == null) { Log.Warn($"[DeviceService] 安全关机失败: 设备 {deviceId} 驱动不存在"); return; } // 2. 验证预约 if (!_resourceManager.ValidateOwner(owner, resourceKey)) { Log.Warn($"[DeviceService] 安全关机权限验证失败: Device={deviceId}, Owner={owner.OwnerId}"); return; } // 3. 获取租约 using var lease = await _resourceManager.AcquireOperationAsync(owner, resourceKey, ct).ConfigureAwait(false); // 4. 发送安全关闭命令 Log.Info($"[DeviceService] 发送安全关闭命令: Device={deviceId}"); await driver.SendCommandAsync("OUTP OFF", ct).ConfigureAwait(false); // 5. 等待确认(短暂延迟确保命令执行完成) await Task.Delay(500, ct).ConfigureAwait(false); // 6. 验证关闭状态 var statusResponse = await driver.QueryAsync("OUTP?", ct).ConfigureAwait(false); Log.Info($"[DeviceService] 设备 {deviceId} 关闭状态确认: {statusResponse}"); Log.Info($"[DeviceService] 安全关机完成: Device={deviceId}"); } catch (OperationCanceledException) { Log.Warn($"[DeviceService] 安全关机操作被取消: Device={deviceId}"); throw; } catch (Exception ex) { Log.Error($"[DeviceService] 安全关机异常: Device={deviceId}, 错误: {ex.Message}", ex); throw; } } } }