78542ab2d2
First review at 7286d320. -001 (High): record ToString() leaked SharedSecret into logs ->
override ToString() that omits it. -003 (Medium): [Range(1,65535)] on Port. -004 thumbprint
doc. -002 (SHA-1 pin -> SHA-256, lives in FrameChannel) deferred cross-module.
72 lines
3.8 KiB
C#
72 lines
3.8 KiB
C#
using System.ComponentModel.DataAnnotations;
|
||
|
||
namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client;
|
||
|
||
/// <summary>
|
||
/// Connection options for <c>WonderwareHistorianClient</c>.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// <para>
|
||
/// <b>Retry / backoff ownership (finding 006):</b> this module performs exactly one
|
||
/// in-place transport reconnect inside <c>FrameChannel.InvokeAsync</c> with no delay,
|
||
/// and does NOT implement exponential reconnect backoff. Broader retry/backoff is the
|
||
/// caller's responsibility — the alarm drain worker
|
||
/// (<c>Core.AlarmHistorian.SqliteStoreAndForwardSink</c>) and the read-side
|
||
/// history router are expected to layer their own backoff on top.
|
||
/// </para>
|
||
/// </remarks>
|
||
/// <param name="Host">Sidecar TCP host (DNS name or IP) the client dials.</param>
|
||
/// <param name="Port">Sidecar TCP port (matches the sidecar's <c>OTOPCUA_HISTORIAN_TCP_PORT</c>). Valid range: 1–65535.</param>
|
||
/// <param name="SharedSecret">Per-process shared secret the sidecar will verify in the Hello frame.</param>
|
||
/// <param name="PeerName">Diagnostic peer identifier sent in Hello — typically the OtOpcUa instance id.</param>
|
||
/// <param name="ConnectTimeout">Cap on the TCP connect + Hello round trip on each (re)connect.</param>
|
||
/// <param name="CallTimeout">Cap on a single read/write call once connected.</param>
|
||
public sealed record WonderwareHistorianClientOptions(
|
||
string Host,
|
||
[Range(1, 65535)] int Port,
|
||
string SharedSecret,
|
||
string PeerName = "OtOpcUa",
|
||
TimeSpan? ConnectTimeout = null,
|
||
TimeSpan? CallTimeout = null)
|
||
{
|
||
/// <summary>Gets the effective connect timeout, using the default if not explicitly set.</summary>
|
||
public TimeSpan EffectiveConnectTimeout => ConnectTimeout ?? TimeSpan.FromSeconds(10);
|
||
|
||
/// <summary>Gets the effective call timeout, using the default if not explicitly set.</summary>
|
||
public TimeSpan EffectiveCallTimeout => CallTimeout ?? TimeSpan.FromSeconds(30);
|
||
|
||
/// <summary>
|
||
/// 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.
|
||
/// </summary>
|
||
[Display(Name = "Probe timeout (seconds)", Description = "Connection test timeout. Default 15s.", GroupName = "Diagnostics")]
|
||
[Range(1, 60)]
|
||
public int ProbeTimeoutSeconds { get; init; } = 15;
|
||
|
||
/// <summary>When true, the client wraps the TCP stream in TLS before the Hello handshake.</summary>
|
||
public bool UseTls { get; init; }
|
||
|
||
/// <summary>
|
||
/// 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
|
||
/// <see cref="UseTls"/> is true, the client validates the cert chain normally
|
||
/// (CA-issued cert).
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// The consumer matches against <c>X509Certificate.GetCertHashString()</c> (SHA-1, 40
|
||
/// hex chars). Supplying a SHA-256 thumbprint (64 hex chars, the format shown by modern
|
||
/// tooling such as <c>certutil</c> 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.
|
||
/// </remarks>
|
||
public string? ServerCertThumbprint { get; init; }
|
||
|
||
/// <inheritdoc/>
|
||
/// <remarks>
|
||
/// Redacts <see cref="SharedSecret"/> so the value cannot appear in log output when the
|
||
/// options object is passed to a structured-logging statement.
|
||
/// </remarks>
|
||
public override string ToString() =>
|
||
$"WonderwareHistorianClientOptions {{ Host={Host}, Port={Port}, PeerName={PeerName}, UseTls={UseTls}, ServerCertThumbprint={ServerCertThumbprint ?? "<null>"} }}";
|
||
}
|