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);
}
}