using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace ZB.MOM.WW.ScadaBridge.SiteEventLogging; public static class ServiceCollectionExtensions { /// /// Register site event logging services (recording, purge, query). /// /// The DI service collection to register into. /// The same for chaining. public static IServiceCollection AddSiteEventLogging(this IServiceCollection services) { // The recorder is registered as a concrete singleton and the interface is // forwarded to the same instance. The purge and query services depend on the // concrete SiteEventLogger directly (they need its lock-guarded WithConnection) // rather than downcasting an ISiteEventLogger, which would throw // InvalidCastException for any other ISiteEventLogger implementation. services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService()); services.AddSingleton(); // The purge service registers on every host node and purges its own // site_events file on every tick, on every node (arch-review 2026-08-19 P4-4 — // the standby writes site_events too, so it can no longer skip its own purge). // It still consults an optional SiteEventLogActiveNodeCheck, but only to annotate // the tick's log line, not to gate it. The Host registers the real active-node // check on site nodes; tests and non-clustered hosts leave it unregistered, and // the log line just reports every tick as active. Building the service via a // factory so the optional delegate flows from DI rather than the constructor default. // // SiteEventLogReplicationCheck flows the same way and is likewise Host-supplied: // it only selects the wording of the purge log line (whether to add the // "expect a transient LocalDb oplog backlog" note), and this component has no // view of LocalDb:Replication. Unregistered ⇒ no note, matching the default // that replication is opt-in and off. services.AddHostedService(sp => new EventLogPurgeService( sp.GetRequiredService(), sp.GetRequiredService>(), sp.GetRequiredService>(), sp.GetService(), sp.GetService())); return services; } // NOTE: EventLogHandlerActor is wired up directly in // ZB.MOM.WW.ScadaBridge.Host/Actors/AkkaHostedService.cs as a cluster singleton, because the // actor must be created inside the ActorSystem with the resolved // IEventLogQueryService. There is intentionally no DI helper for that here — a // former AddSiteEventLoggingActors placeholder was dead code and has been removed. }