| | |
| | | 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; |
| | |
| | | { |
| | | log.Info("开始初始化基础设施服务..."); |
| | | |
| | | // 1. 创建 ResourceManager 单例 |
| | | var resourceManager = new ResourceManager(); |
| | | // 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("ResourceManager 已注册"); |
| | | log.Info("LayeredResourceManager (基于 DbLeaseStore) 已注册"); |
| | | |
| | | // 2. 创建 DeviceManager 单例 |
| | | var deviceManager = new DeviceManager(); |
| | |
| | | UtilContainer.RegisterUtil("PowerSupplyService", powerSupplyService); |
| | | log.Info("PowerSupplyService 已注册"); |
| | | |
| | | // 6. 从数据库加载设备定义并注册驱动 |
| | | // 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("基础设施服务初始化完成"); |
| | |
| | | } |
| | | |
| | | /// <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) |