wenxiangchao
4 天以前 559890c482f5973f06aafdfec9550fee5ba3c7f2
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
219
220
221
222
223
using System.IO;
using log4net;
using HMI.Core.Util;
using Aging.Infrastructure.Broker;
using Aging.Infrastructure.Contracts;
using Aging.Infrastructure.Core;
using Aging.Infrastructure.Services;
using Aging.Infrastructure.Drivers;
 
namespace Aging.Infrastructure
{
    /// <summary>
    /// 基础设施启动引导 - 初始化并注册所有核心服务到 UtilContainer
    /// </summary>
    public static class InfrastructureBootstrapper
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(InfrastructureBootstrapper));
        private static bool _initialized = false;
 
        /// <summary>
        /// 初始化基础设施服务
        /// 应在 WPF 主程序启动时或插件 InitFinish 中调用
        /// </summary>
        /// <param name="deviceConfigDbPath">DeviceConfig 插件的 SQLite 数据库路径</param>
        public static void Initialize(string deviceConfigDbPath)
        {
            if (_initialized)
            {
                log.Warn("基础设施已初始化,跳过重复初始化");
                return;
            }
 
            try
            {
                log.Info("开始初始化基础设施服务...");
 
                // V3.0 MVP:仲裁库 arb.db(与 data.db 同目录)
                string arbPath = Path.Combine(Path.GetDirectoryName(deviceConfigDbPath)!, "arb.db");
                var leaseStore = new DbLeaseStore(arbPath, "local-main");
                // V3.0 INV-03:启动对账——上次进程异常退出未释放的租约在本机宿主更替后自动回收,
                // 避免调试/生产维护被 RecoveryRequired 永久阻塞(证据写入 recovery_checkpoint)
                leaseStore.ReconcileAfterBoot($"{Environment.MachineName}/{System.Diagnostics.Process.GetCurrentProcess().Id}");
                var resourceManager = new LayeredResourceManager(leaseStore);
                UtilContainer.RegisterUtil("LeaseCoordinator", leaseStore);
                UtilContainer.RegisterUtil("ResourceManager", resourceManager);
                log.Info("LayeredResourceManager (基于 DbLeaseStore) 已注册");
 
                // 2. 创建 DeviceManager 单例
                var deviceManager = new DeviceManager();
                UtilContainer.RegisterUtil("DeviceManager", deviceManager);
                log.Info("DeviceManager 已注册");
 
                // 3. 创建 SlotDeviceMappingResolver(需要 DeviceConfig DB 路径)
                var mappingResolver = new SlotDeviceMappingResolver(deviceConfigDbPath);
                UtilContainer.RegisterUtil("SlotDeviceMappingResolver", mappingResolver);
                log.Info("SlotDeviceMappingResolver 已注册");
 
                // 4. 创建 DeviceService
                var deviceService = new DeviceService(resourceManager, deviceManager, mappingResolver);
                UtilContainer.RegisterUtil("DeviceService", deviceService);
                log.Info("DeviceService 已注册");
 
                // 5. 创建 PowerSupplyService
                var powerSupplyService = new PowerSupplyService(resourceManager, deviceManager, mappingResolver);
                UtilContainer.RegisterUtil("PowerSupplyService", powerSupplyService);
                log.Info("PowerSupplyService 已注册");
 
                // 6. 创建 AutoDeviceFacade (自动化测试入口)
                var autoFacade = new AutoDeviceFacade(resourceManager, deviceService);
                UtilContainer.RegisterUtil("AutoDeviceFacade", autoFacade);
                log.Info("AutoDeviceFacade 已注册");
 
                // 7. 创建 CanBusService (CAN 类型化服务)
                var canBusService = new CanBusService(autoFacade);
                UtilContainer.RegisterUtil("CanBusService", canBusService);
                log.Info("CanBusService 已注册");
 
                // 8. 从数据库加载设备定义并注册驱动
                LoadDevicesFromConfig(deviceManager, mappingResolver);
 
                // 8.5. V3.0 混合架构:Broker 域设备注册代理驱动(物理会话由 DeviceBroker.exe 宿主唯一持有)
                RegisterBrokeredDrivers(deviceManager, deviceConfigDbPath);
 
                _initialized = true;
                log.Info("基础设施服务初始化完成");
            }
            catch (Exception ex)
            {
                log.Error("基础设施初始化失败", ex);
                throw;
            }
        }
 
        /// <summary>
        /// V3.0:扫描配置库中 ExecutionMode=Broker 的设备,注册统一 CanDeviceDriver(BrokerRpc 代理后端)。
        /// Local 设备保持现有直驱路径不变;Broker 宿主未启动时代理仅在发起 I/O 时失败,不阻塞初始化。
        /// </summary>
        private static void RegisterBrokeredDrivers(IDeviceManager deviceManager, string deviceConfigDbPath)
        {
            try
            {
                if (!File.Exists(deviceConfigDbPath)) return;
 
                var brokeredDevices = new System.Collections.Generic.List<(string DeviceId, string BrokerId, string Endpoint)>();
                using (var conn = new System.Data.SQLite.SQLiteConnection(
                           $"Data Source={deviceConfigDbPath};Version=3;Read Only=True;"))
                {
                    conn.Open();
                    using var cmd = conn.CreateCommand();
                    cmd.CommandText = "SELECT DeviceId, BrokerId, Endpoint FROM DeviceDefinition WHERE ExecutionMode = 'Broker';";
                    using var rd = cmd.ExecuteReader();
                    while (rd.Read())
                    {
                        string id = rd.GetString(0);
                        string brokerId = rd.IsDBNull(1) ? "" : rd.GetString(1);
                        string endpoint = rd.IsDBNull(2) ? "" : rd.GetString(2);
                        if (!string.IsNullOrWhiteSpace(brokerId))
                            brokeredDevices.Add((id, brokerId, endpoint));
                    }
                }
 
                if (brokeredDevices.Count == 0) return;
 
                // INV-04:客户端侧生效配置快照,随每次 RPC 提交供 Broker 对账
                string configHash;
                try { configHash = DeviceConfigHash.Compute(deviceConfigDbPath); }
                catch { configHash = ""; }
 
                foreach (var (deviceId, brokerId, endpoint) in brokeredDevices)
                {
                    if (deviceManager.GetDriver(deviceId) != null) continue;
                    var driver = CanDeviceDriver.CreateBrokerProxy(deviceId, endpoint, BrokerPipeName.For(brokerId), configHash);
                    deviceManager.RegisterDriver(deviceId, driver);
                    log.Info($"[Bootstrapper] 设备 {deviceId} 已注册 Broker 代理驱动 (管道={BrokerPipeName.For(brokerId)}, hash={configHash.Substring(0, Math.Min(8, configHash.Length))})");
                }
            }
            catch (Exception ex)
            {
                // 代理注册失败降级:不影响 Local 直驱设备链路
                log.Warn($"[Bootstrapper] Broker 代理驱动注册失败(Broker 链路不可用,Local 设备不受影响): {ex.Message}", ex);
            }
        }
 
        /// <summary>
        /// 从 DeviceConfig 数据库加载设备定义并注册驱动
        /// </summary>
        private static void LoadDevicesFromConfig(IDeviceManager deviceManager, SlotDeviceMappingResolver mappingResolver)
        {
            try
            {
                // 读取所有设备映射
                var mappings = mappingResolver.GetAllMappings();
                // 从映射中提取唯一的设备ID
                var deviceIds = mappings
                    .Select(m => m.DeviceId)
                    .Distinct()
                    .ToList();
 
                int loaded = 0;
                foreach (var deviceId in deviceIds)
                {
                    try
                    {
                        // 这里暂时使用通用 TCP 驱动作为占位
                        // 实际应该从 device_definition 表读取 transport 和 endpoint
                        // 然后通过 DriverFactory.CreateDriver 创建对应驱动
                        //
                        // TODO: 从数据库读取设备详细信息(transport, endpoint)
                        // var device = GetDeviceDefinition(deviceId);
                        // var driver = DriverFactory.CreateDriver(deviceId, device.Transport, device.Endpoint);
 
                        log.Debug($"设备 {deviceId} 驱动注册待配置详细信息");
                        loaded++;
                    }
                    catch (Exception ex)
                    {
                        log.Error($"注册设备 {deviceId} 驱动失败: {ex.Message}", ex);
                    }
                }
 
                log.Info($"从设备配置加载了 {loaded} 个设备驱动");
            }
            catch (Exception ex)
            {
                log.Error("加载设备配置失败", ex);
            }
        }
 
        /// <summary>
        /// 注册单个设备驱动(供外部调用,用于动态添加设备)
        /// </summary>
        public static void RegisterDevice(string deviceId, string transport, string endpoint)
        {
            var container = new UtilContainer();
            var deviceManager = container.GetUtil<IDeviceManager>("DeviceManager");
            if (deviceManager == null)
            {
                log.Error("DeviceManager 未初始化");
                return;
            }
 
            try
            {
                var driver = DriverFactory.CreateDriver(deviceId, transport, endpoint);
                deviceManager.RegisterDriver(deviceId, driver);
                log.Info($"设备 {deviceId} ({transport}) 驱动已注册");
            }
            catch (Exception ex)
            {
                log.Error($"注册设备 {deviceId} 失败: {ex.Message}", ex);
            }
        }
 
        /// <summary>
        /// 重置基础设施(用于测试或重新初始化)
        /// </summary>
        public static void Reset()
        {
            _initialized = false;
            log.Info("基础设施已重置");
        }
    }
}