using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using ZB.MOM.WW.ScadaBridge.Communication.Grpc; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories; using ZB.MOM.WW.ScadaBridge.SiteRuntime.Deployment; using ZB.MOM.WW.ScadaBridge.SiteRuntime.Persistence; using ZB.MOM.WW.ScadaBridge.SiteRuntime.Repositories; using ZB.MOM.WW.ScadaBridge.SiteRuntime.Scripts; using ZB.MOM.WW.ScadaBridge.SiteRuntime.Streaming; namespace ZB.MOM.WW.ScadaBridge.SiteRuntime; public static class ServiceCollectionExtensions { /// /// Registers Site Runtime services including SiteStorageService for SQLite persistence. /// The caller must register an or call the /// overload with an explicit connection string. /// /// The DI service collection to register services into. /// The same to allow chaining. public static IServiceCollection AddSiteRuntime(this IServiceCollection services) { // SiteStorageService is registered by the Host using AddSiteRuntime(connectionString) // This overload is for backward compatibility / skeleton placeholder return services; } /// /// Registers Site Runtime services with an explicit SQLite connection string. /// /// The DI service collection to register services into. /// The SQLite connection string for the site local storage database. /// The same to allow chaining. public static IServiceCollection AddSiteRuntime(this IServiceCollection services, string siteDbConnectionString) { services.AddSingleton(sp => { var logger = sp.GetRequiredService>(); return new SiteStorageService(siteDbConnectionString, logger); }); services.AddHostedService(); // Script compilation service services.AddSingleton(); // Shared script library services.AddSingleton(); // Site stream manager — registered as singleton and exposed as ISiteStreamSubscriber // so the gRPC server can subscribe relay actors to instance events. // ActorSystem is injected later via Initialize() after AkkaHostedService starts. services.AddSingleton(sp => { var options = sp.GetRequiredService>().Value; var logger = sp.GetRequiredService>(); return new SiteStreamManager(options, logger); }); services.AddSingleton(sp => sp.GetRequiredService()); // Site-local cached-operation tracking store — the SQLite source of truth // that Tracking.Status(TrackedOperationId) reads and the cached-call telemetry // forwarder writes. Registered HERE (site-only) so the two comments that claim // "the operational tracking store is registered by AddSiteRuntime" are true // again (AuditLog SCE + AkkaHostedService). Before this (arch-review 08 round 2 // NF4/T8) it had no DI registration anywhere in src/, so every consumer resolved // it as null and silently ran degraded (no cached-drain, no PullSiteCalls // reconciliation, Tracking.Status audit-only). Central roots never call // AddSiteRuntime, so this stays absent on central — matching the SITE-ONLY // contract. OperationTrackingOptions is bound + validated by the Host's // SiteServiceRegistration site-options block. services.AddSingleton(); // Site-local repository implementations backed by SQLite services.AddScoped(); // Notify-and-fetch: typed HttpClient for fetching deployment configs from central. services.AddHttpClient() .ConfigureHttpClient((sp, c) => c.Timeout = TimeSpan.FromSeconds( sp.GetRequiredService>().Value.ConfigFetchTimeoutSeconds)); // S2/UA5: periodically lift the shared script-execution scheduler gauges // (queue depth, busy threads, oldest-busy age) onto the site health report. // Registered via factory-lambda so ISiteHealthCollector (registered by the // Host's AddSiteHealthMonitoring) is resolved lazily at host start. services.AddHostedService(sp => new ScriptSchedulerStatsReporter( sp.GetRequiredService(), sp.GetRequiredService>().Value, sp.GetRequiredService>())); return services; } /// Registers any additional DI services needed by the Site Runtime Akka actors. /// The DI service collection to register services into. /// The same to allow chaining. public static IServiceCollection AddSiteRuntimeActors(this IServiceCollection services) { // Actor registration is handled by AkkaHostedService.RegisterSiteActors() // which creates the DeploymentManager singleton and proxy return services; } }