using System.Diagnostics;
|
using Aging.Infrastructure.Contracts;
|
using log4net;
|
|
namespace Aging.Infrastructure.Services
|
{
|
/// <summary>
|
/// 设备服务实现。
|
/// 协调 ResourceManager、DeviceManager 和 SlotMapping,
|
/// 提供面向 DeviceId 的命令执行、查询和安全关机功能。
|
/// 所有操作均需通过资源预约验证和租约管理,确保硬件资源的安全访问。
|
/// </summary>
|
public sealed class DeviceService : IDeviceService
|
{
|
private static readonly ILog Log = LogManager.GetLogger(typeof(DeviceService));
|
|
/// <summary>
|
/// 资源管理器
|
/// </summary>
|
private readonly IResourceManager _resourceManager;
|
|
/// <summary>
|
/// 设备管理器
|
/// </summary>
|
private readonly IDeviceManager _deviceManager;
|
|
/// <summary>
|
/// Slot-设备-通道映射解析器
|
/// </summary>
|
private readonly SlotDeviceMappingResolver _slotMappingResolver;
|
|
/// <summary>
|
/// 初始化设备服务实例
|
/// </summary>
|
/// <param name="resourceManager">资源管理器</param>
|
/// <param name="deviceManager">设备管理器</param>
|
/// <param name="slotMappingResolver">Slot 映射解析器</param>
|
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));
|
}
|
|
/// <inheritdoc/>
|
public async Task<DeviceCommandResult> 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
|
};
|
}
|
}
|
|
/// <inheritdoc/>
|
public async Task<DeviceCommandResult> 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
|
};
|
}
|
}
|
|
/// <inheritdoc/>
|
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;
|
}
|
}
|
}
|
}
|