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("基础设施已重置");
|
}
|
}
|
}
|