From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点
---
Aging.Infrastructure/Services/DeviceService.cs | 331 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 331 insertions(+), 0 deletions(-)
diff --git a/Aging.Infrastructure/Services/DeviceService.cs b/Aging.Infrastructure/Services/DeviceService.cs
new file mode 100644
index 0000000..2902549
--- /dev/null
+++ b/Aging.Infrastructure/Services/DeviceService.cs
@@ -0,0 +1,331 @@
+using System.Diagnostics;
+using Aging.Infrastructure.Contracts;
+using log4net;
+
+namespace Aging.Infrastructure.Services
+{
+ /// <summary>
+ /// 璁惧鏈嶅姟瀹炵幇銆�
+ /// 鍗忚皟 ResourceManager銆丏eviceManager 鍜� 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-璁惧-閫氶亾鏄犲皠瑙f瀽鍣�
+ /// </summary>
+ private readonly SlotDeviceMappingResolver _slotMappingResolver;
+
+ /// <summary>
+ /// 鍒濆鍖栬澶囨湇鍔″疄渚�
+ /// </summary>
+ /// <param name="resourceManager">璧勬簮绠$悊鍣�</param>
+ /// <param name="deviceManager">璁惧绠$悊鍣�</param>
+ /// <param name="slotMappingResolver">Slot 鏄犲皠瑙f瀽鍣�</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;
+ }
+ }
+ }
+}
--
Gitblit v1.9.1