feat(localdb): wire AddOtOpcUaLocalDb into the driver role
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZB.MOM.WW.LocalDb;
|
||||
using ZB.MOM.WW.LocalDb.Replication;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Host.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Single registration point for the node-local LocalDb subsystem: the embedded SQLite store
|
||||
/// that caches the deployed-configuration artifact, plus the optional gRPC replication that
|
||||
/// mirrors it to the node's redundant pair peer.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Exists as a named extension rather than inline <c>AddZbLocalDb</c> calls in
|
||||
/// <c>Program.cs</c> so the wiring is covered by a DI resolution test — <c>Program.cs</c> is
|
||||
/// top-level statements and cannot be exercised directly, which is exactly how a
|
||||
/// "registered but never resolvable" defect ships unnoticed. This family has shipped that
|
||||
/// defect three times (Secrets 0.2.0, Secrets 0.2.2, ScadaBridge #22).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Driver-role nodes only.</b> Admin-only nodes have no deployed configuration to cache,
|
||||
/// and registering here would impose the <c>LocalDb:Path</c>-required-or-no-boot constraint
|
||||
/// on them for nothing.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Storage is unconditional; replication is default-OFF.</b> A node with no
|
||||
/// <c>PeerAddress</c> and no <c>SyncListenPort</c> is simply a fast local SQLite file —
|
||||
/// <c>AddZbLocalDbReplication</c> registers the engine but it stays idle. Replication is
|
||||
/// opt-in per pair because there is no production distribution story for the sync
|
||||
/// <c>ApiKey</c> yet (the same open question the Secrets KEK has).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class LocalDbRegistration
|
||||
{
|
||||
/// <summary>Configuration section holding <c>LocalDbOptions</c>.</summary>
|
||||
public const string LocalDbSectionPath = "LocalDb";
|
||||
|
||||
/// <summary>Configuration section holding <c>ReplicationOptions</c>.</summary>
|
||||
public const string ReplicationSectionPath = "LocalDb:Replication";
|
||||
|
||||
/// <summary>
|
||||
/// Configuration key carrying the dedicated h2c sync listener's port. Zero or absent means
|
||||
/// no listener is bound and the passive sync endpoint is not mapped.
|
||||
/// </summary>
|
||||
public const string SyncListenPortKey = "LocalDb:SyncListenPort";
|
||||
|
||||
/// <summary>
|
||||
/// The port the dedicated cleartext-HTTP/2 sync listener should bind, or <c>0</c> when the
|
||||
/// node should not listen at all. Defaults to <c>0</c> — absent configuration must mean
|
||||
/// "off".
|
||||
/// </summary>
|
||||
/// <param name="configuration">The application configuration.</param>
|
||||
/// <returns>The configured sync port, or <c>0</c>.</returns>
|
||||
public static int SyncListenPort(IConfiguration configuration)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(configuration);
|
||||
return configuration.GetValue(SyncListenPortKey, defaultValue: 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers the local database (with the deployment-cache schema applied and registered for
|
||||
/// replication) and the replication engine.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <see cref="LocalDbSetup.OnReady"/> runs inside <c>AddZbLocalDb</c>'s singleton factory,
|
||||
/// before the first caller receives the <c>ILocalDb</c> — so every consumer is guaranteed
|
||||
/// to see the tables created and their capture triggers installed.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <c>AddZbLocalDbReplication</c> is called unconditionally rather than behind an
|
||||
/// <c>Enabled</c> flag because the library already models "off" as "no
|
||||
/// <c>PeerAddress</c>": the initiator background service idles and the passive endpoint
|
||||
/// is only reachable if <c>Program.cs</c> maps it, which it does only when
|
||||
/// <see cref="SyncListenPortKey"/> is set. Adding a second gate on top would give two
|
||||
/// ways to express the same thing and a way for them to disagree.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="services">The service collection to add to.</param>
|
||||
/// <param name="configuration">The application configuration.</param>
|
||||
/// <returns>The same <paramref name="services"/> instance, for chaining.</returns>
|
||||
public static IServiceCollection AddOtOpcUaLocalDb(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(services);
|
||||
ArgumentNullException.ThrowIfNull(configuration);
|
||||
|
||||
services.AddZbLocalDb(configuration, LocalDbSetup.OnReady);
|
||||
services.AddZbLocalDbReplication(configuration);
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user