New project src/ZB.MOM.WW.OtOpcUa.Core.Abstractions (.NET 10, BCL-only dependencies, GenerateDocumentationFile=true, TreatWarningsAsErrors=true) defining the contract surface every driver implements. Per docs/v2/plan.md decisions #4 (composable capability interfaces), #52 (streaming IAddressSpaceBuilder), #53 (capability discovery via `is` checks no flag enum), #54 (optional IRediscoverable sub-interface), #59 (Core.Abstractions internal-only for now design as if public). Eleven capability interfaces: - IDriver — required lifecycle / health / config-apply / memory-footprint accounting (per driver-stability.md Tier A/B allocation tracking) - ITagDiscovery — discovers tags streaming to IAddressSpaceBuilder - IReadable — on-demand reads idempotent for Polly retry - IWritable — writes NOT auto-retried by default per decisions #44 + #45 - ISubscribable — data-change subscriptions covering both native (Galaxy MXAccess advisory, OPC UA monitored items, TwinCAT ADS) and driver-internal polled (Modbus, AB CIP, S7, FOCAS) mechanisms; OnDataChange callback regardless of source - IAlarmSource — alarm events + acknowledge + AlarmSeverity enum mirroring acl-design.md NodePermissions alarm-severity values - IHistoryProvider — HistoryReadRaw + HistoryReadProcessed with continuation points - IRediscoverable — opt-in change-detection signal; static drivers don't implement - IHostConnectivityProbe — generalized from Galaxy's GalaxyRuntimeProbeManager per plan §5a - IDriverConfigEditor — Admin UI plug-point for per-driver custom config editors deferred to each driver's phase per decision #27 - IAddressSpaceBuilder — streaming builder API for driver-driven address-space construction Plus DTOs: DriverDataType, SecurityClassification (mirroring v1 Galaxy model), DriverAttributeInfo (replaces Galaxy-specific GalaxyAttributeInfo per plan §5a), DriverHealth + DriverState, DataValueSnapshot (universal OPC UA quality + timestamp carrier per decision #13), HostConnectivityStatus + HostState + HostStatusChangedEventArgs, RediscoveryEventArgs, DataChangeEventArgs, AlarmEventArgs + AlarmAcknowledgeRequest + AlarmSeverity, WriteRequest + WriteResult, HistoryReadResult + HistoryAggregateType, ISubscriptionHandle + IAlarmSubscriptionHandle + IVariableHandle. DriverTypeRegistry singleton with Register / Get / TryGet / All; thread-safe via Interlocked.Exchange snapshot replacement on registration; case-insensitive lookups; rejects duplicate registrations; rejects empty type names. DriverTypeMetadata record carries TypeName + AllowedNamespaceKinds (NamespaceKindCompatibility flags enum per decision #111) + per-config-tier JSON Schemas the validator checks at draft-publish time (decision #91). Tests project tests/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests (xUnit v3 1.1.0 matching existing test projects). 24 tests covering: 1) interface independence reflection check (no references outside BCL/System; all public types in root namespace; every capability interface is public); 2) DriverTypeRegistry round-trip, case-insensitive lookups, KeyNotFoundException on unknown, null on TryGet of unknown, InvalidOperationException on duplicate registration (case-insensitive too), All() enumeration, NamespaceKindCompatibility bitmask combinations, ArgumentException on empty type names. Build: 0 errors, 4 warnings (only pre-existing transitive package vulnerability + analyzer hints). Full test suite: 845 passing / 1 failing — strict improvement over Phase 0 baseline (821/1) by the 24 new Core.Abstractions tests; no regressions in any other test project. Phase 1 entry-gate record (docs/v2/implementation/entry-gate-phase-1.md) documents the deviation: only Stream A executed in this continuation since Streams B-E need SQL Server / GLAuth / Galaxy infrastructure standup per dev-environment.md Step 1, which is currently TODO. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
3.1 KiB
C#
61 lines
3.1 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
/// <summary>
|
|
/// Required capability for every driver instance. Owns lifecycle, metadata, health.
|
|
/// Other capabilities (<see cref="ITagDiscovery"/>, <see cref="IReadable"/>,
|
|
/// <see cref="IWritable"/>, <see cref="ISubscribable"/>, <see cref="IAlarmSource"/>,
|
|
/// <see cref="IHistoryProvider"/>, <see cref="IRediscoverable"/>,
|
|
/// <see cref="IHostConnectivityProbe"/>) are composable — a driver implements only what its
|
|
/// backend actually supports.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Per <c>docs/v2/plan.md</c> decisions #4 (composable capability interfaces) and #53
|
|
/// (capability discovery via <c>is</c> checks — no redundant flag enum).
|
|
/// </remarks>
|
|
public interface IDriver
|
|
{
|
|
/// <summary>Stable logical ID of this driver instance, sourced from the central config DB.</summary>
|
|
string DriverInstanceId { get; }
|
|
|
|
/// <summary>Driver type name (e.g. "Galaxy", "ModbusTcp", "AbCip"). Matches <c>DriverInstance.DriverType</c>.</summary>
|
|
string DriverType { get; }
|
|
|
|
/// <summary>Initialize the driver from its <c>DriverConfig</c> JSON; open connections; prepare for first use.</summary>
|
|
Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken);
|
|
|
|
/// <summary>
|
|
/// Apply a config change in place without tearing down the driver process.
|
|
/// Used by <c>IGenerationApplier</c> when only this driver's config changed in the new generation.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Per <c>docs/v2/driver-stability.md</c> §"In-process only (Tier A/B)" — Reinitialize is the
|
|
/// only Core-initiated recovery path for in-process drivers; if it fails, the driver instance
|
|
/// is marked Faulted and its nodes go Bad quality, but the server process keeps running.
|
|
/// </remarks>
|
|
Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken);
|
|
|
|
/// <summary>Stop the driver, close connections, release resources. Called on shutdown or driver removal.</summary>
|
|
Task ShutdownAsync(CancellationToken cancellationToken);
|
|
|
|
/// <summary>Current health snapshot, polled by Core for the status dashboard and ServiceLevel.</summary>
|
|
DriverHealth GetHealth();
|
|
|
|
/// <summary>
|
|
/// Approximate driver-attributable footprint in bytes (caches, queues, symbol tables).
|
|
/// Polled every 30s by Core; on cache-budget breach, Core asks the driver to flush via
|
|
/// <see cref="FlushOptionalCachesAsync"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Per <c>docs/v2/driver-stability.md</c> §"In-process only (Tier A/B) — driver-instance
|
|
/// allocation tracking". Tier C drivers (process-isolated) report through the same
|
|
/// interface but the cache-flush is internal to their host.
|
|
/// </remarks>
|
|
long GetMemoryFootprint();
|
|
|
|
/// <summary>
|
|
/// Drop optional caches (symbol cache, browse cache, etc.) to bring footprint back below budget.
|
|
/// Required-for-correctness state must NOT be flushed.
|
|
/// </summary>
|
|
Task FlushOptionalCachesAsync(CancellationToken cancellationToken);
|
|
}
|