using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ZB.MOM.WW.OtOpcUa.Configuration;
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
using ZB.MOM.WW.OtOpcUa.Core.AlarmHistorian;
using ZB.MOM.WW.OtOpcUa.Core.Hosting;
using ZB.MOM.WW.OtOpcUa.Core.OpcUa;
using ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms;
using ZB.MOM.WW.OtOpcUa.Server.OpcUa;
namespace ZB.MOM.WW.OtOpcUa.Server.Phase7;
///
/// Phase 7 follow-up (task #246) — orchestrates the runtime composition of virtual
/// tags + scripted alarms + the historian sink + the driver-bridge that feeds the
/// engines. Called by after the bootstrap generation
/// loads + before .
///
///
///
/// reads Script / VirtualTag / ScriptedAlarm rows from
/// the central config DB at the bootstrapped generation, instantiates a
/// , runs ,
/// starts a per registered driver feeding
/// 's tag rows into the cache, and returns
/// the engine-backed sources for
/// .
///
///
/// tears down the bridge first (so no more events
/// arrive at the cache), then the engines (so cascades + timer ticks stop), then
/// the SQLite sink (which flushes any in-flight drain). Lifetime is owned by the
/// host; calls dispose during graceful
/// shutdown.
///
///
public sealed class Phase7Composer : IAsyncDisposable
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly DriverHost _driverHost;
private readonly DriverEquipmentContentRegistry _equipmentRegistry;
private readonly IAlarmHistorianSink _historianSink;
private readonly ILoggerFactory _loggerFactory;
private readonly Serilog.ILogger _scriptLogger;
private readonly ILogger _logger;
private DriverSubscriptionBridge? _bridge;
private Phase7ComposedSources _sources = Phase7ComposedSources.Empty;
// Sink we constructed in PrepareAsync (vs. the injected fallback). Held so
// DisposeAsync can flush + tear down the SQLite drain timer.
private SqliteStoreAndForwardSink? _ownedSink;
private bool _disposed;
public Phase7Composer(
IServiceScopeFactory scopeFactory,
DriverHost driverHost,
DriverEquipmentContentRegistry equipmentRegistry,
IAlarmHistorianSink historianSink,
ILoggerFactory loggerFactory,
Serilog.ILogger scriptLogger,
ILogger logger)
{
_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
_driverHost = driverHost ?? throw new ArgumentNullException(nameof(driverHost));
_equipmentRegistry = equipmentRegistry ?? throw new ArgumentNullException(nameof(equipmentRegistry));
_historianSink = historianSink ?? throw new ArgumentNullException(nameof(historianSink));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_scriptLogger = scriptLogger ?? throw new ArgumentNullException(nameof(scriptLogger));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Phase7ComposedSources Sources => _sources;
public async Task PrepareAsync(long generationId, CancellationToken ct)
{
if (_disposed) throw new ObjectDisposedException(nameof(Phase7Composer));
// Load the three Phase 7 row sets in one DB scope.
List