using Microsoft.Extensions.Configuration; namespace ZB.MOM.WW.OtOpcUa.Runtime; /// /// The ONE definition of "this node's LocalDb is replicated to a peer" (#603). Two consumers must agree /// on it, and used to carry separate predicates that diverged: the Host's table-registration step /// (LocalDbSetup.ReplicationIsConfigured - which nodes capture changes) and the alarm-historian /// drain gate (AddAlarmHistorian - which nodes stand down in favour of a peer). Lives in Runtime /// because Host references Runtime and not the reverse. /// /// /// /// Predicate: LocalDb:Replication:PeerAddress OR LocalDb:Replication:ApiKey is /// non-blank. The OR is required: only the dialling half of a pair sets PeerAddress, while /// the passive half carries the shared ApiKey (plus a listen port) and nothing else. /// /// /// Why the drain gate takes the same predicate (it previously used PeerAddress OR /// SyncListenPort). The gate's question is "does a peer hold the same rows?". The passive /// sync endpoint is fail-closed on the key, so a node with a listen port but no ApiKey rejects /// every inbound stream and shares its queue with nobody - gating it would park its alarm events /// behind a Primary that cannot deliver them. Conversely an ApiKey-only passive node IS /// registered and does receive its peer's rows, so it must be gated or both halves drain. The port /// is not evidence of a peer; the key is. /// /// public static class LocalDbReplicationPolicy { /// Configuration section holding the LocalDb replication options. public const string ReplicationSectionPath = "LocalDb:Replication"; /// Whether this node's LocalDb replicates to a pair peer. /// The application configuration. /// true when PeerAddress or ApiKey is set under the replication section. public static bool IsConfigured(IConfiguration configuration) { ArgumentNullException.ThrowIfNull(configuration); var section = configuration.GetSection(ReplicationSectionPath); return !string.IsNullOrWhiteSpace(section["PeerAddress"]) || !string.IsNullOrWhiteSpace(section["ApiKey"]); } }