Merge feat/676-opcuaclient-followups: endpoint host+port rewrite, TCP-stall wire test, ReconnectPeriod removed, IDriverConnectionLossSource fast recovery, trailing re-read, replay summary (#676)

This commit is contained in:
Joseph Doherty
2026-10-11 11:45:26 -04:00
22 changed files with 1876 additions and 117 deletions
@@ -0,0 +1,31 @@
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
/// <summary>
/// Optional driver capability (Gitea #676) — a driver that can tell, from its protocol, that its connection is
/// DEFINITIVELY gone (it can never recover in place, only a re-initialise brings it back) raises
/// <see cref="ConnectionLost"/> so the host re-initialises it at once instead of waiting out the #527 comms-loss
/// watchdog (~90 s of frozen <see cref="DriverHealth.LastSuccessfulRead"/>).
/// </summary>
/// <remarks>
/// <para>
/// <b>Definitive only.</b> An AMBIGUOUS failure — a timeout, a stalled socket, "no communication" — must NOT
/// raise: the connection may yet resume in place (a <c>docker pause</c>, a congested link), and tearing it
/// down would cost the session, its subscriptions and the in-place recovery. Ambiguous failures keep going
/// through the watchdog, whose conjunction (non-Healthy AND a frozen read stamp) is the honest test for them.
/// </para>
/// <para>
/// The host (<c>DriverInstanceActor</c>) acts on a raise only while the driver is Connected — in any other
/// state a re-initialise is already pending or running — and it subscribes for its own lifetime, not per
/// connect, because the <see cref="IDriver"/> instance can outlive the actor. A driver should raise at most
/// once per connection and re-arm when it is re-initialised.
/// </para>
/// </remarks>
public interface IDriverConnectionLossSource
{
/// <summary>Raised (on the driver's own thread) when the driver's connection is definitively lost.</summary>
event EventHandler<DriverConnectionLossEventArgs>? ConnectionLost;
}
/// <summary>Event payload for <see cref="IDriverConnectionLossSource.ConnectionLost"/>.</summary>
/// <param name="Reason">Driver-supplied reason for the diagnostic log (e.g. the protocol status that proved the loss).</param>
public sealed record DriverConnectionLossEventArgs(string Reason);