namespace ZB.MOM.WW.OtOpcUa.Server.Redundancy; /// /// Latest observed reachability of the peer node per the Phase 6.3 Stream B.1/B.2 two-layer /// probe model. HTTP layer is the fast-fail; UA layer is authoritative. /// /// /// Fed into the as peerHttpHealthy + /// peerUaHealthy. The concrete probe loops (PeerHttpProbeLoop + /// PeerUaProbeLoop) live in a Stream B runtime follow-up — this type is the /// contract the publisher reads; probers write via /// . /// public sealed record PeerReachability(bool HttpHealthy, bool UaHealthy) { public static readonly PeerReachability Unknown = new(false, false); public static readonly PeerReachability FullyHealthy = new(true, true); /// True when both probes report healthy — the ServiceLevelCalculator's peerReachable gate. public bool BothHealthy => HttpHealthy && UaHealthy; } /// /// Thread-safe holder of the latest per peer NodeId. Probe /// loops call ; the reads via /// . /// public sealed class PeerReachabilityTracker { private readonly System.Collections.Concurrent.ConcurrentDictionary _byPeer = new(StringComparer.OrdinalIgnoreCase); public void Update(string peerNodeId, PeerReachability reachability) { ArgumentException.ThrowIfNullOrWhiteSpace(peerNodeId); _byPeer[peerNodeId] = reachability ?? throw new ArgumentNullException(nameof(reachability)); } /// Current reachability for a peer. Returns when not yet probed. public PeerReachability Get(string peerNodeId) => _byPeer.TryGetValue(peerNodeId, out var r) ? r : PeerReachability.Unknown; }