feat(dcl): MxGateway client seam interfaces + global options

This commit is contained in:
Joseph Doherty
2026-05-29 07:44:07 -04:00
parent f626ece66a
commit fe02ec5664
2 changed files with 90 additions and 0 deletions
@@ -0,0 +1,79 @@
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol;
namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters;
/// <summary>Connection parameters resolved from the flat config dict.</summary>
public record MxGatewayConnectionOptions(
string Endpoint, string ApiKey, string ClientName, int WriteUserId,
bool UseTls, string? CaFile, string? ServerName, int ReadTimeoutMs);
/// <summary>One advised-tag value change pushed from the gateway event stream.</summary>
public record MxValueUpdate(string TagPath, object? Value, QualityCode Quality, DateTimeOffset Timestamp);
/// <summary>Per-tag read outcome.</summary>
public record MxReadOutcome(string TagPath, bool Success, object? Value, QualityCode Quality, DateTimeOffset Timestamp, string? Error);
/// <summary>Per-tag write outcome.</summary>
public record MxWriteOutcome(string TagPath, bool Success, string? Error);
/// <summary>One node in a Galaxy browse level.</summary>
public record MxBrowseChild(string NodeId, string DisplayName, BrowseNodeClass NodeClass, bool HasChildren);
/// <summary>
/// Seam over the MxAccess Gateway .NET client + Galaxy repository client. Decouples
/// <see cref="MxGatewayDataConnection"/> from the generated gRPC/protobuf types so the
/// adapter is unit-testable with a fake. The real implementation lives in
/// <c>RealMxGatewayClient</c>.
/// </summary>
public interface IMxGatewayClient : IAsyncDisposable
{
/// <summary>Opens the gateway session and registers the client (Register → serverHandle held internally).</summary>
/// <param name="options">Resolved connection parameters.</param>
/// <param name="ct">Cancellation token.</param>
Task ConnectAsync(MxGatewayConnectionOptions options, CancellationToken ct = default);
/// <summary>Closes the session.</summary>
/// <param name="ct">Cancellation token.</param>
Task DisconnectAsync(CancellationToken ct = default);
/// <summary>AddItem + Advise; returns the gateway item handle (as a string subscription id).</summary>
/// <param name="tagPath">Tag address to subscribe to.</param>
/// <param name="ct">Cancellation token.</param>
Task<string> SubscribeAsync(string tagPath, CancellationToken ct = default);
/// <summary>UnAdvise + RemoveItem for a previously returned subscription id.</summary>
/// <param name="subscriptionId">Subscription id returned by <see cref="SubscribeAsync"/>.</param>
/// <param name="ct">Cancellation token.</param>
Task UnsubscribeAsync(string subscriptionId, CancellationToken ct = default);
/// <summary>Snapshot read of one or more tags (ReadBulk).</summary>
/// <param name="tagPaths">Tag addresses to read.</param>
/// <param name="ct">Cancellation token.</param>
Task<IReadOnlyList<MxReadOutcome>> ReadAsync(IReadOnlyList<string> tagPaths, CancellationToken ct = default);
/// <summary>Write one or more tag/value pairs (WriteBulk with the configured WriteUserId).</summary>
/// <param name="writes">Tag/value pairs to write.</param>
/// <param name="ct">Cancellation token.</param>
Task<IReadOnlyList<MxWriteOutcome>> WriteAsync(IReadOnlyList<(string TagPath, object? Value)> writes, CancellationToken ct = default);
/// <summary>One Galaxy browse level (BrowseChildren). <paramref name="parentNodeId"/> null → root.</summary>
/// <param name="parentNodeId">Parent node id (Galaxy contained path), or null for root.</param>
/// <param name="ct">Cancellation token.</param>
Task<(IReadOnlyList<MxBrowseChild> Children, bool Truncated)> BrowseChildrenAsync(string? parentNodeId, CancellationToken ct = default);
/// <summary>
/// Long-running event consumer. Invokes <paramref name="onUpdate"/> for each advised-tag
/// data change. Resumes from the last delivered worker sequence on reconnect. Completes
/// (or throws) when the stream ends — the adapter treats that as a disconnect.
/// </summary>
/// <param name="onUpdate">Callback invoked per advised-tag value change.</param>
/// <param name="ct">Cancellation token; ends the loop when cancelled.</param>
Task RunEventLoopAsync(Action<MxValueUpdate> onUpdate, CancellationToken ct = default);
}
/// <summary>Builds <see cref="IMxGatewayClient"/> instances.</summary>
public interface IMxGatewayClientFactory
{
/// <summary>Creates a new, unconnected client instance.</summary>
IMxGatewayClient Create();
}
@@ -0,0 +1,11 @@
namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer;
/// <summary>
/// Deployment-wide MxGateway defaults, bound from the "MxGateway" section of
/// appsettings.json. Per-endpoint behavior lives on MxGatewayEndpointConfig.
/// </summary>
public class MxGatewayGlobalOptions
{
/// <summary>Prefix used to derive a per-connection client registration name when the connection's ClientName is blank.</summary>
public string ClientNamePrefix { get; set; } = "scadabridge";
}