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 { /// /// 基础设施启动引导 - 初始化并注册所有核心服务到 UtilContainer /// public static class InfrastructureBootstrapper { private static readonly ILog log = LogManager.GetLogger(typeof(InfrastructureBootstrapper)); private static bool _initialized = false; /// /// 初始化基础设施服务 /// 应在 WPF 主程序启动时或插件 InitFinish 中调用 /// /// DeviceConfig 插件的 SQLite 数据库路径 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; } } /// /// V3.0:扫描配置库中 ExecutionMode=Broker 的设备,注册统一 CanDeviceDriver(BrokerRpc 代理后端)。 /// Local 设备保持现有直驱路径不变;Broker 宿主未启动时代理仅在发起 I/O 时失败,不阻塞初始化。 /// 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); } } /// /// 从 DeviceConfig 数据库加载设备定义并注册驱动 /// 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); } } /// /// 注册单个设备驱动(供外部调用,用于动态添加设备) /// public static void RegisterDevice(string deviceId, string transport, string endpoint) { var container = new UtilContainer(); var deviceManager = container.GetUtil("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); } } /// /// 重置基础设施(用于测试或重新初始化) /// public static void Reset() { _initialized = false; log.Info("基础设施已重置"); } } }