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