using System.ComponentModel.DataAnnotations; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Config; /// /// Driver-instance options for the in-process .NET 10 Galaxy driver. Maps to the /// DriverConfig JSON column on the central config DB. Decomposed into nested /// records so the JSON structure mirrors the runtime shape and operators can target /// individual sections (gateway endpoint, mxaccess client identity, reconnect policy) /// without touching the rest. /// /// Connection details for the MxAccess gateway (mxaccessgw repo). /// MXAccess-specific knobs surfaced through gw — client name, publishing interval, write-user. /// Galaxy Repository browse options consumed by the discoverer. /// Backoff knobs for the in-driver reconnect supervisor (PR 4.5). public sealed record GalaxyDriverOptions( GalaxyGatewayOptions Gateway, GalaxyMxAccessOptions MxAccess, GalaxyRepositoryOptions Repository, GalaxyReconnectOptions Reconnect) { /// /// Timeout for the AdminUI Test Connect probe, in seconds. The AdminUI clamps to a /// 60s server-side maximum; this default is what the form pre-fills for new instances. /// [Display(Name = "Probe timeout (seconds)", Description = "Connection test timeout. Default 30s.", GroupName = "Diagnostics")] [Range(1, 60)] public int ProbeTimeoutSeconds { get; init; } = 30; } /// /// Connection details for the MxAccess gateway. is /// resolved by GalaxyDriver.ResolveApiKey at InitializeAsync time. Four forms /// supported, in priority order: /// /// env:NAME — read from an environment variable (recommended for /// production; the central config DB holds only the indirection, not the key). /// file:PATH — read from an ACL'd file outside the repo. /// dev:KEY — explicit cleartext opt-in for dev rigs / parity tests; /// no startup warning. /// Anything else — treated as a literal cleartext API key for back-compat. /// The resolver emits a Warning at startup so an operator who accidentally /// committed a cleartext key sees it; production should migrate to env: /// or file:. /// /// // PR 6.5 tuning notes: // ConnectTimeoutSeconds = 10 — cold-start network path comfort margin; soak runs // never saw a successful connect take >2s, so 10s is generous without being lax. // DefaultCallTimeoutSeconds = 30 — bumped from 5s because a 50k-tag SubscribeBulk // can exceed 5s under MxAccess COM contention (the worker walks the gw item list // serially under the apartment lock). 30s leaves comfortable headroom for the // legitimate worst case while still failing fast on a wedged worker. // StreamTimeoutSeconds = 0 — unlimited; the StreamEvents RPC must run for the // lifetime of the driver. Set a finite value only for diagnostic runs. public sealed record GalaxyGatewayOptions( string Endpoint, string ApiKeySecretRef, bool UseTls = true, string? CaCertificatePath = null, int ConnectTimeoutSeconds = 10, int DefaultCallTimeoutSeconds = 30, int StreamTimeoutSeconds = 0); /// /// MXAccess-specific knobs the gateway forwards to the worker process. /// /// /// Wonderware client identity. MUST be unique per OtOpcUa instance — when two instances /// share a name, the older session loses subscription state. Redundancy pairs (decision /// #149) enforce uniqueness via install scripts. /// /// /// Hint forwarded as buffered_update_interval_ms on subscribe; lets the worker /// coalesce updates at the OPC UA publishing cadence rather than every COM tick. /// /// /// Reserved for ArchestrA secured-write user mapping; PR 4.3 wires WriteSecured /// routing against this id. 0 = anonymous. /// /// /// Bounded-channel size between the EventPump's network-read loop and its listener /// fan-out loop (PR 6.2). Default 50_000 = one second of headroom at 50k tags / 1Hz; /// raise it when galaxy.events.dropped shows up under transient consumer /// slowness, lower it on a memory-tight host where the headroom isn't needed. /// Must be ≥ 1 — EventPump enforces this at construction and throws /// if the value is zero or negative. /// public sealed record GalaxyMxAccessOptions( string ClientName, int PublishingIntervalMs = 1000, int WriteUserId = 0, [Range(1, int.MaxValue)] int EventPumpChannelCapacity = 50_000); /// /// Galaxy Repository browse-side knobs consumed by PR 4.1's GalaxyDiscoverer. /// public sealed record GalaxyRepositoryOptions( int DiscoverPageSize = 5000, bool WatchDeployEvents = true); /// /// Backoff knobs for the in-driver reconnect supervisor (PR 4.5). Replay-on-session-lost /// calls the gw's ReplaySubscriptions RPC after reconnect rather than re-issuing /// subscribe-bulk for every tag. /// public sealed record GalaxyReconnectOptions( int InitialBackoffMs = 500, int MaxBackoffMs = 30_000, bool ReplayOnSessionLost = true);