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;
}
}
}
}