wenxiangchao
2026-11-02 fe2aa4880d5c9fd88088ad0ed81ebaca05629f5f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
using System.Data;
using Aging.Infrastructure.Contracts;
using HMI.Core.Util;
using log4net;
 
namespace Aging.Infrastructure.Services
{
    /// <summary>
    /// 电源端点信息,描述 Slot 映射到的具体设备通道
    /// </summary>
    public sealed class PowerEndpoint
    {
        /// <summary>
        /// 设备标识符
        /// </summary>
        public string DeviceId { get; }
 
        /// <summary>
        /// 通道标识
        /// </summary>
        public int ChannelId { get; }
 
        /// <summary>
        /// 生效版本号
        /// </summary>
        public string EffectiveVersion { get; }
 
        /// <summary>
        /// 初始化电源端点实例
        /// </summary>
        /// <param name="deviceId">设备标识符</param>
        /// <param name="channelId">通道标识</param>
        /// <param name="effectiveVersion">生效版本号</param>
        public PowerEndpoint(string deviceId, int channelId, string effectiveVersion)
        {
            DeviceId = deviceId ?? throw new ArgumentNullException(nameof(deviceId));
            ChannelId = channelId;
            EffectiveVersion = effectiveVersion ?? string.Empty;
        }
 
        /// <summary>
        /// 转换为资源键,用于资源管理器的预约和租约操作
        /// </summary>
        /// <returns>对应的资源键实例</returns>
        public ResourceKey ToResourceKey()
        {
            return new ResourceKey(DeviceId, "PowerSupply", ChannelId.ToString());
        }
 
        /// <inheritdoc/>
        public override string ToString() => $"{DeviceId}:CH{ChannelId}(v{EffectiveVersion})";
    }
 
    /// <summary>
    /// Slot-设备-通道映射解析器。
    /// 从 Plugin.DeviceConfig 的 SQLite 数据库读取 Slot-Device-Channel 映射关系,
    /// 提供根据 SlotId 和能力类型解析具体设备端点的功能。
    /// </summary>
    public sealed class SlotDeviceMappingResolver
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(SlotDeviceMappingResolver));
 
        /// <summary>
        /// DeviceConfig 的 SQLite 数据库文件路径
        /// </summary>
        private readonly string _deviceConfigDbPath;
 
        /// <summary>
        /// 初始化映射解析器实例
        /// </summary>
        /// <param name="deviceConfigDbPath">DeviceConfig 的 SQLite 数据库文件路径</param>
        public SlotDeviceMappingResolver(string deviceConfigDbPath)
        {
            _deviceConfigDbPath = deviceConfigDbPath ?? throw new ArgumentNullException(nameof(deviceConfigDbPath));
            Log.Info($"[SlotDeviceMappingResolver] 初始化完成,数据库路径: {deviceConfigDbPath}");
        }
 
        /// <summary>
        /// 根据 SlotId 和能力类型解析具体的电源端点。
        /// 从 slot_device_mapping 表查询匹配的最新版本映射记录。
        /// </summary>
        /// <param name="slotId">Slot 标识符</param>
        /// <param name="capability">能力类型(如 "PowerSupply")</param>
        /// <returns>解析后的电源端点;未找到匹配映射时返回 null</returns>
        public PowerEndpoint? ResolveEndpoint(string slotId, string capability)
        {
            if (string.IsNullOrWhiteSpace(slotId))
                throw new ArgumentException("SlotId 不能为空", nameof(slotId));
            if (string.IsNullOrWhiteSpace(capability))
                throw new ArgumentException("能力类型不能为空", nameof(capability));
 
            SqliteHelper? sqliteHelper = null;
            try
            {
                sqliteHelper = new SqliteHelper(_deviceConfigDbPath);
 
                var sql = $"SELECT slot_id, capability, version, device_id, channel_id, mapping_version " +
                          $"FROM slot_device_mapping " +
                          $"WHERE slot_id = '{slotId}' AND capability = '{capability}' " +
                          $"ORDER BY mapping_version DESC LIMIT 1";
 
                var dataTable = sqliteHelper.GetDataTable(sql);
 
                if (dataTable.Rows.Count == 0)
                {
                    Log.Warn($"[SlotDeviceMappingResolver] 未找到 Slot={slotId}, Capability={capability} 的映射记录");
                    return null;
                }
 
                var row = dataTable.Rows[0];
                var deviceId = row["device_id"]?.ToString() ?? string.Empty;
                var channelId = Convert.ToInt32(row["channel_id"]);
                var effectiveVersion = row["mapping_version"]?.ToString() ?? string.Empty;
 
                var endpoint = new PowerEndpoint(deviceId, channelId, effectiveVersion);
 
                Log.Info($"[SlotDeviceMappingResolver] 解析映射: Slot={slotId}, Capability={capability} → {endpoint}");
                return endpoint;
            }
            catch (Exception ex)
            {
                Log.Error($"[SlotDeviceMappingResolver] 解析映射失败: Slot={slotId}, Capability={capability}, 错误: {ex.Message}", ex);
                throw;
            }
            finally
            {
                sqliteHelper?.Close();
            }
        }
 
        /// <summary>
        /// 获取数据库中所有的 Slot-设备-通道映射记录
        /// </summary>
        /// <returns>所有映射记录的列表</returns>
        public List<PowerEndpoint> GetAllMappings()
        {
            SqliteHelper? sqliteHelper = null;
            try
            {
                sqliteHelper = new SqliteHelper(_deviceConfigDbPath);
 
                var sql = "SELECT slot_id, capability, version, device_id, channel_id, mapping_version " +
                          "FROM slot_device_mapping " +
                          "ORDER BY slot_id, capability, mapping_version DESC";
 
                var dataTable = sqliteHelper.GetDataTable(sql);
                var results = new List<PowerEndpoint>();
 
                foreach (DataRow row in dataTable.Rows)
                {
                    var deviceId = row["device_id"]?.ToString() ?? string.Empty;
                    var channelId = Convert.ToInt32(row["channel_id"]);
                    var effectiveVersion = row["mapping_version"]?.ToString() ?? string.Empty;
 
                    results.Add(new PowerEndpoint(deviceId, channelId, effectiveVersion));
                }
 
                Log.Info($"[SlotDeviceMappingResolver] 获取全部映射记录,共 {results.Count} 条");
                return results;
            }
            catch (Exception ex)
            {
                Log.Error($"[SlotDeviceMappingResolver] 获取全部映射记录失败: {ex.Message}", ex);
                throw;
            }
            finally
            {
                sqliteHelper?.Close();
            }
        }
 
        /// <summary>
        /// 按能力类型筛选映射记录
        /// </summary>
        /// <param name="capability">能力类型(如 "PowerSupply"、"CAN" 等)</param>
        /// <returns>匹配指定能力类型的映射记录列表</returns>
        public List<PowerEndpoint> GetMappingsByCapability(string capability)
        {
            if (string.IsNullOrWhiteSpace(capability))
                throw new ArgumentException("能力类型不能为空", nameof(capability));
 
            SqliteHelper? sqliteHelper = null;
            try
            {
                sqliteHelper = new SqliteHelper(_deviceConfigDbPath);
 
                var sql = $"SELECT slot_id, capability, version, device_id, channel_id, mapping_version " +
                          $"FROM slot_device_mapping " +
                          $"WHERE capability = '{capability}' " +
                          $"ORDER BY slot_id, mapping_version DESC";
 
                var dataTable = sqliteHelper.GetDataTable(sql);
                var results = new List<PowerEndpoint>();
 
                foreach (DataRow row in dataTable.Rows)
                {
                    var deviceId = row["device_id"]?.ToString() ?? string.Empty;
                    var channelId = Convert.ToInt32(row["channel_id"]);
                    var effectiveVersion = row["mapping_version"]?.ToString() ?? string.Empty;
 
                    results.Add(new PowerEndpoint(deviceId, channelId, effectiveVersion));
                }
 
                Log.Info($"[SlotDeviceMappingResolver] 按能力类型 {capability} 筛选映射记录,共 {results.Count} 条");
                return results;
            }
            catch (Exception ex)
            {
                Log.Error($"[SlotDeviceMappingResolver] 按能力类型筛选映射记录失败: {ex.Message}", ex);
                throw;
            }
            finally
            {
                sqliteHelper?.Close();
            }
        }
    }
}