using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; using ZB.MOM.WW.OtOpcUa.Core.Hosting; namespace ZB.MOM.WW.OtOpcUa.Host.Drivers; // Probe type aliases — keep the using list concise. using ModbusProbe = Driver.Modbus.ModbusDriverProbe; using AbCipProbe = Driver.AbCip.AbCipDriverProbe; using AbLegacyProbe = Driver.AbLegacy.AbLegacyDriverProbe; using S7Probe = Driver.S7.S7DriverProbe; using TwinCATProbe = Driver.TwinCAT.TwinCATDriverProbe; using FocasProbe = Driver.FOCAS.FocasDriverProbe; using OpcUaProbe = Driver.OpcUaClient.OpcUaClientDriverProbe; using GalaxyProbe = Driver.Galaxy.GalaxyDriverProbe; using HistorianProbe = Driver.Historian.Wonderware.Client.WonderwareHistorianDriverProbe; /// /// Wires every cross-platform driver assembly's Register(registry, loggerFactory) /// extension into a single singleton and binds the /// v2 abstraction to a /// over it. Replaces the F7 seam's NullDriverFactory default so deploys actually /// materialise real instances on driver-role nodes. /// /// The factory registry is skipped on admin-only nodes — they never run drivers, so it doesn't /// need to exist (Program.cs guards via the hasDriver flag). The driver probe /// set is the exception: it backs the AdminUI Test Connect button and so must also be wired on /// admin nodes — see . /// public static class DriverFactoryBootstrap { /// /// Register the cross-platform driver factories + bind . /// Must be called BEFORE services.AddAkka so the runtime extension can resolve /// from DI when spawning DriverHostActor. /// /// The service collection to register driver factories with. public static IServiceCollection AddOtOpcUaDriverFactories(this IServiceCollection services) { services.AddSingleton(sp => { var registry = new DriverFactoryRegistry(); var loggerFactory = sp.GetService(); Register(registry, loggerFactory); return registry; }); services.AddSingleton(sp => new DriverFactoryRegistryAdapter(sp.GetRequiredService())); // Driver nodes also carry the probe set so a fused admin,driver node has it; the admin-only // case is covered by Program.cs calling AddOtOpcUaDriverProbes() in the hasAdmin block. services.AddOtOpcUaDriverProbes(); return services; } /// /// Register one per driver type. These back the AdminUI's /// "Test Connect" button: the admin-operations cluster singleton resolves /// of and dispatches by DriverType. /// /// That singleton is role-pinned to admin, so this MUST be wired on admin nodes — /// including admin-only nodes that lack the driver role (e.g. the MAIN cluster's /// admin-a/admin-b). Probes are lightweight (cheap connect, no persistent state) and don't /// need the driver-factory registry, so they register independently of /// . /// /// /// Uses TryAddEnumerable so a fused admin,driver node — which reaches this from both /// the driver-factory path and the admin path — registers each probe exactly once. A /// duplicate would make the singleton's ToDictionary(p => p.DriverType) throw. /// /// /// The service collection to register driver probes with. public static IServiceCollection AddOtOpcUaDriverProbes(this IServiceCollection services) { services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); return services; } /// /// Invoke every cross-platform driver's Register extension. New driver assemblies /// get added here — one line per type. ShouldStub() in DriverInstanceActor still /// handles platform/role-dependent stubbing (e.g. Galaxy on macOS), so registering a /// factory here doesn't mean it always runs in production. /// private static void Register(DriverFactoryRegistry registry, ILoggerFactory? loggerFactory) { Driver.AbCip.AbCipDriverFactoryExtensions.Register(registry); Driver.AbLegacy.AbLegacyDriverFactoryExtensions.Register(registry, loggerFactory); Driver.FOCAS.FocasDriverFactoryExtensions.Register(registry); Driver.Galaxy.GalaxyDriverFactoryExtensions.Register(registry, loggerFactory); Driver.Modbus.ModbusDriverFactoryExtensions.Register(registry, loggerFactory); Driver.S7.S7DriverFactoryExtensions.Register(registry); Driver.TwinCAT.TwinCATDriverFactoryExtensions.Register(registry); } }