b75e013d0a
The old AdminUI cannot author the per-driver transport key (#576), so the 'pin before upgrading' recipe had no working path. A node-level appsetting (env Drivers__AbCip__DefaultTransport) now supplies the default for AbCip drivers with no key: explicit key > node default > compiled Native. Bound and validated unconditionally (bad value fails host start); the driver factory and the Test Connect probe both read it so they agree. AbCip.md upgrade recipe rewritten around the key; Configuration.md documents it. Also documents first-wins for AllowPacking/probe and host-alias throttles (final review M6) and moves the status-bit note out of AbCip.md (M5). Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
66 lines
3.9 KiB
C#
66 lines
3.9 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
|
|
|
/// <summary>
|
|
/// The ONE place an AbCip driver's effective transport is decided from its configured
|
|
/// <see cref="AbCipDriverOptions.Transport"/>. The driver constructor, the Test Connect probe and the
|
|
/// CLI (through the driver) all resolve through here, so they cannot disagree about what an absent
|
|
/// <c>transport</c> key means.
|
|
/// <para>Precedence (final review I1): an explicit per-driver <c>transport</c> key wins; otherwise the
|
|
/// node-level default (<c>Drivers:AbCip:DefaultTransport</c>, read in the Host composition root and passed
|
|
/// in as <c>nodeDefault</c>); otherwise the compiled <see cref="Default"/>.</para>
|
|
/// </summary>
|
|
public static class AbCipTransportResolver
|
|
{
|
|
/// <summary>The compiled default: the transport an absent key selects when no node default is configured.</summary>
|
|
public const AbCipTransport Default = AbCipTransport.Native;
|
|
|
|
/// <summary>Returns the effective transport: an explicit value always wins; null means <paramref name="nodeDefault"/>.</summary>
|
|
/// <param name="configured">The configured transport, or null for "use the default".</param>
|
|
/// <param name="nodeDefault">The node-level default for drivers with no key (the compiled <see cref="Default"/> unless pinned).</param>
|
|
/// <returns>The transport the driver runs on.</returns>
|
|
public static AbCipTransport Resolve(AbCipTransport? configured, AbCipTransport nodeDefault = Default) =>
|
|
configured ?? nodeDefault;
|
|
|
|
/// <summary>Returns the effective transport for <paramref name="options"/>.</summary>
|
|
/// <param name="options">The driver options.</param>
|
|
/// <param name="nodeDefault">The node-level default for drivers with no key.</param>
|
|
/// <returns>The transport the driver runs on.</returns>
|
|
public static AbCipTransport Resolve(AbCipDriverOptions options, AbCipTransport nodeDefault = Default)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(options);
|
|
return Resolve(options.Transport, nodeDefault);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses a transport name the way the driver-config <c>transport</c> key and the node-level default
|
|
/// are parsed: a defined enum NAME, case-insensitive. Numeric strings ("0", "7") and the flags form
|
|
/// ("Native,Libplctag") are rejected — <c>Enum.TryParse</c> alone accepts both.
|
|
/// </summary>
|
|
/// <param name="raw">The raw value.</param>
|
|
/// <param name="transport">The parsed transport.</param>
|
|
/// <returns>True when <paramref name="raw"/> names a transport.</returns>
|
|
public static bool TryParse(string? raw, out AbCipTransport transport)
|
|
{
|
|
transport = Default;
|
|
if (string.IsNullOrWhiteSpace(raw)) return false;
|
|
// Exact name match only: Enum.TryParse would also accept "1" and the flags form "Native,Libplctag".
|
|
var name = Enum.GetNames<AbCipTransport>()
|
|
.FirstOrDefault(n => string.Equals(n, raw.Trim(), StringComparison.OrdinalIgnoreCase));
|
|
return name is not null && Enum.TryParse(name, out transport);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Operator-facing description of the configured-vs-effective transport for the init log line:
|
|
/// <c>Native (default)</c> when the key was absent and the compiled default applies,
|
|
/// <c>Libplctag (node default)</c> when the key was absent and the node pinned a different default,
|
|
/// <c>Native (configured)</c> when the key was explicit.
|
|
/// </summary>
|
|
/// <param name="configured">The configured transport, or null.</param>
|
|
/// <param name="nodeDefault">The node-level default.</param>
|
|
/// <returns>A short description.</returns>
|
|
public static string Describe(AbCipTransport? configured, AbCipTransport nodeDefault = Default) =>
|
|
configured is not null ? $"{configured} (configured)"
|
|
: nodeDefault == Default ? $"{nodeDefault} (default)"
|
|
: $"{nodeDefault} (node default)";
|
|
}
|