using System.ComponentModel.DataAnnotations; namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client; /// /// Connection options for WonderwareHistorianClient. /// /// /// /// Retry / backoff ownership (finding 006): this module performs exactly one /// in-place transport reconnect inside FrameChannel.InvokeAsync with no delay, /// and does NOT implement exponential reconnect backoff. Broader retry/backoff is the /// caller's responsibility — the alarm drain worker /// (Core.AlarmHistorian.SqliteStoreAndForwardSink) and the read-side /// history router are expected to layer their own backoff on top. /// /// /// Sidecar TCP host (DNS name or IP) the client dials. /// Sidecar TCP port (matches the sidecar's OTOPCUA_HISTORIAN_TCP_PORT). Valid range: 1–65535. /// Per-process shared secret the sidecar will verify in the Hello frame. /// Diagnostic peer identifier sent in Hello — typically the OtOpcUa instance id. /// Cap on the TCP connect + Hello round trip on each (re)connect. /// Cap on a single read/write call once connected. public sealed record WonderwareHistorianClientOptions( string Host, [Range(1, 65535)] int Port, string SharedSecret, string PeerName = "OtOpcUa", TimeSpan? ConnectTimeout = null, TimeSpan? CallTimeout = null) { /// Gets the effective connect timeout, using the default if not explicitly set. public TimeSpan EffectiveConnectTimeout => ConnectTimeout ?? TimeSpan.FromSeconds(10); /// Gets the effective call timeout, using the default if not explicitly set. public TimeSpan EffectiveCallTimeout => CallTimeout ?? TimeSpan.FromSeconds(30); /// /// 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 15s.", GroupName = "Diagnostics")] [Range(1, 60)] public int ProbeTimeoutSeconds { get; init; } = 15; /// When true, the client wraps the TCP stream in TLS before the Hello handshake. public bool UseTls { get; init; } /// /// Optional SHA-1 thumbprint (40 hex characters, no spaces, case-insensitive) the client /// pins the sidecar's TLS server cert against. When null/empty and /// is true, the client validates the cert chain normally /// (CA-issued cert). /// /// /// The consumer matches against X509Certificate.GetCertHashString() (SHA-1, 40 /// hex chars). Supplying a SHA-256 thumbprint (64 hex chars, the format shown by modern /// tooling such as certutil or Windows Certificate Manager) will never match and /// will cause the TLS handshake to fail silently. Only 40-character SHA-1 hex strings /// are accepted. /// public string? ServerCertThumbprint { get; init; } /// /// /// Redacts so the value cannot appear in log output when the /// options object is passed to a structured-logging statement. /// public override string ToString() => $"WonderwareHistorianClientOptions {{ Host={Host}, Port={Port}, PeerName={PeerName}, UseTls={UseTls}, ServerCertThumbprint={ServerCertThumbprint ?? ""} }}"; }