docs(xmldoc): fill missing XML docs + strip tracking-ID comments across src
v2-ci / build (push) Failing after 41s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
v2-ci / build (push) Failing after 41s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>/<param>/<returns>/<inheritdoc> where missing and removes project bookkeeping IDs (task/tracking refs) from shipped code comments, so the docs read cleanly and CommentChecker is quiet except for known false positives (PLC/protocol terms, event/IEqualityComparer inheritdoc). Doc/comment-only; no logic changed; solution builds clean.
This commit is contained in:
@@ -67,11 +67,13 @@ public abstract class CommandBase : ICommand
|
||||
/// Executes the command-specific workflow against the configured OPC UA endpoint.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public abstract ValueTask ExecuteAsync(IConsole console);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ConnectionSettings" /> from the common command options.
|
||||
/// </summary>
|
||||
/// <returns>The connection settings built from the current command options.</returns>
|
||||
protected ConnectionSettings CreateConnectionSettings()
|
||||
{
|
||||
var securityMode = SecurityModeMapper.FromString(Security);
|
||||
@@ -97,6 +99,7 @@ public abstract class CommandBase : ICommand
|
||||
/// and returns both the service and the connection info.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts connection setup for the command.</param>
|
||||
/// <returns>The connected client service along with its connection info.</returns>
|
||||
protected async Task<(IOpcUaClientService Service, ConnectionInfo Info)> CreateServiceAndConnectAsync(
|
||||
CancellationToken ct)
|
||||
{
|
||||
|
||||
@@ -36,10 +36,7 @@ public class AcknowledgeCommand : CommandBase
|
||||
[CommandOption("comment", 'c', Description = "Operator comment for the acknowledgment")]
|
||||
public string Comment { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server and acknowledges the specified alarm condition.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
ConfigureLogging();
|
||||
|
||||
@@ -38,10 +38,6 @@ public class AlarmsCommand : CommandBase
|
||||
[CommandOption("refresh", Description = "Request a ConditionRefresh after subscribing")]
|
||||
public bool Refresh { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server, subscribes to alarm events, and streams operator-facing alarm state changes to the console.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
|
||||
@@ -36,10 +36,7 @@ public class ConfirmCommand : CommandBase
|
||||
[CommandOption("comment", 'c', Description = "Operator comment for the confirmation")]
|
||||
public string Comment { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server and confirms the specified acknowledged alarm condition.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
ConfigureLogging();
|
||||
|
||||
@@ -24,10 +24,7 @@ public class DisableCommand : CommandBase
|
||||
[CommandOption("node", 'n', Description = "Condition node ID of the alarm to disable", IsRequired = true)]
|
||||
public string NodeId { get; init; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server and disables the specified alarm condition.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
ConfigureLogging();
|
||||
|
||||
@@ -24,10 +24,7 @@ public class EnableCommand : CommandBase
|
||||
[CommandOption("node", 'n', Description = "Condition node ID of the alarm to enable", IsRequired = true)]
|
||||
public string NodeId { get; init; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server and enables the specified alarm condition.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
ConfigureLogging();
|
||||
|
||||
@@ -15,7 +15,6 @@ public class RedundancyCommand : CommandBase
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Connects to the server and prints redundancy mode, service level, and partner-server identity data.</summary>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
|
||||
@@ -38,10 +38,7 @@ public class ShelveCommand : CommandBase
|
||||
[CommandOption("duration", 'd', Description = "Shelving duration in seconds (must be > 0; in seconds, converted to milliseconds for the OPC UA call; required for --kind Timed)")]
|
||||
public double DurationSeconds { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server and shelves or unshelves the specified alarm condition.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
ConfigureLogging();
|
||||
|
||||
@@ -31,10 +31,6 @@ public class WriteCommand : CommandBase
|
||||
[CommandOption("value", 'v', Description = "Value to write", IsRequired = true)]
|
||||
public string Value { get; init; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server, converts the supplied value to the node's current data type, and issues the write.
|
||||
/// </summary>
|
||||
/// <param name="console">The CLI console used for output and cancellation handling.</param>
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask ExecuteAsync(IConsole console)
|
||||
{
|
||||
|
||||
+1
-3
@@ -12,9 +12,7 @@ internal sealed class DefaultApplicationConfigurationFactory : IApplicationConfi
|
||||
{
|
||||
private static readonly ILogger Logger = Log.ForContext<DefaultApplicationConfigurationFactory>();
|
||||
|
||||
/// <summary>Creates an OPC UA application configuration from the provided connection settings.</summary>
|
||||
/// <param name="settings">The connection settings to use.</param>
|
||||
/// <param name="ct">Token to cancel the operation.</param>
|
||||
/// <inheritdoc />
|
||||
public async Task<ApplicationConfiguration> CreateAsync(ConnectionSettings settings, CancellationToken ct)
|
||||
{
|
||||
// Resolve the canonical PKI path lazily on first use so constructing a
|
||||
|
||||
@@ -11,10 +11,7 @@ internal sealed class DefaultEndpointDiscovery : IEndpointDiscovery
|
||||
{
|
||||
private static readonly ILogger Logger = Log.ForContext<DefaultEndpointDiscovery>();
|
||||
|
||||
/// <summary>Selects an OPC UA endpoint matching the requested security mode.</summary>
|
||||
/// <param name="config">The application configuration.</param>
|
||||
/// <param name="endpointUrl">The endpoint URL to query.</param>
|
||||
/// <param name="requestedMode">The requested message security mode.</param>
|
||||
/// <inheritdoc />
|
||||
public EndpointDescription SelectEndpoint(ApplicationConfiguration config, string endpointUrl,
|
||||
MessageSecurityMode requestedMode)
|
||||
{
|
||||
@@ -53,6 +50,7 @@ internal static class EndpointSelector
|
||||
/// Thrown when no endpoint matches <paramref name="requestedMode"/>; the message lists the
|
||||
/// security mode + policy combinations the server returned so operators can diagnose mismatches.
|
||||
/// </exception>
|
||||
/// <returns>The best-matching endpoint, with its URL host rewritten to match <paramref name="endpointUrl"/> if needed.</returns>
|
||||
public static EndpointDescription SelectBest(
|
||||
IEnumerable<EndpointDescription> allEndpoints,
|
||||
string endpointUrl,
|
||||
|
||||
@@ -109,7 +109,7 @@ internal sealed class DefaultSessionAdapter : ISessionAdapter
|
||||
byte[] continuationPoint, CancellationToken ct)
|
||||
{
|
||||
// Pass the caller's token so a cancelled browse does not block on the continuation
|
||||
// round-trip (Client.Shared-015).
|
||||
// round-trip.
|
||||
var (_, nextCp, nextRefs) = await _session.BrowseNextAsync(null, false, continuationPoint, ct);
|
||||
return (nextCp, nextRefs ?? []);
|
||||
}
|
||||
|
||||
@@ -11,14 +11,7 @@ internal sealed class DefaultSessionFactory : ISessionFactory
|
||||
{
|
||||
private static readonly ILogger Logger = Log.ForContext<DefaultSessionFactory>();
|
||||
|
||||
/// <summary>Creates a new OPC UA session.</summary>
|
||||
/// <param name="config">The OPC UA application configuration.</param>
|
||||
/// <param name="endpoint">The endpoint description to connect to.</param>
|
||||
/// <param name="sessionName">The name for the session.</param>
|
||||
/// <param name="sessionTimeoutMs">The session timeout in milliseconds.</param>
|
||||
/// <param name="identity">The user identity for the session.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <returns>An adapter wrapping the created session.</returns>
|
||||
/// <inheritdoc />
|
||||
public async Task<ISessionAdapter> CreateSessionAsync(
|
||||
ApplicationConfiguration config,
|
||||
EndpointDescription endpoint,
|
||||
|
||||
@@ -105,7 +105,7 @@ internal sealed class DefaultSubscriptionAdapter : ISubscriptionAdapter
|
||||
{
|
||||
try
|
||||
{
|
||||
// Forward the caller's token so the delete can be cancelled (Client.Shared-014).
|
||||
// Forward the caller's token so the delete can be cancelled.
|
||||
await _subscription.DeleteAsync(true, ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
+1
@@ -13,5 +13,6 @@ internal interface IApplicationConfigurationFactory
|
||||
/// </summary>
|
||||
/// <param name="settings">The connection settings to configure.</param>
|
||||
/// <param name="ct">Cancellation token for the operation.</param>
|
||||
/// <returns>The validated <see cref="ApplicationConfiguration"/>.</returns>
|
||||
Task<ApplicationConfiguration> CreateAsync(ConnectionSettings settings, CancellationToken ct = default);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ internal interface IEndpointDiscovery
|
||||
/// <param name="config">The OPC UA application configuration.</param>
|
||||
/// <param name="endpointUrl">The endpoint URL to discover.</param>
|
||||
/// <param name="requestedMode">The requested message security mode.</param>
|
||||
/// <returns>The best-matching endpoint description, with its URL hostname rewritten to match <paramref name="endpointUrl"/> when they differ.</returns>
|
||||
EndpointDescription SelectEndpoint(ApplicationConfiguration config, string endpointUrl,
|
||||
MessageSecurityMode requestedMode);
|
||||
}
|
||||
@@ -58,6 +58,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node whose current runtime value should be read.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the server read if the client cancels the request.</param>
|
||||
/// <returns>The current data value read from the server.</returns>
|
||||
Task<DataValue> ReadValueAsync(NodeId nodeId, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -66,6 +67,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// <param name="nodeId">The node whose value should be updated.</param>
|
||||
/// <param name="value">The typed OPC UA data value to write to the server.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the write if the client cancels the request.</param>
|
||||
/// <returns>The status code returned by the server for the write operation.</returns>
|
||||
Task<StatusCode> WriteValueAsync(NodeId nodeId, DataValue value, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -75,6 +77,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// <param name="nodeId">The starting node for the hierarchical browse.</param>
|
||||
/// <param name="nodeClassMask">The node classes that should be returned to the caller.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the browse request.</param>
|
||||
/// <returns>A continuation point (or <c>null</c> when complete) and the references found.</returns>
|
||||
Task<(byte[]? ContinuationPoint, ReferenceDescriptionCollection References)> BrowseAsync(
|
||||
NodeId nodeId, uint nodeClassMask = 0, CancellationToken ct = default);
|
||||
|
||||
@@ -83,6 +86,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="continuationPoint">The continuation token returned by a prior browse result page.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the browse-next request.</param>
|
||||
/// <returns>The next continuation point (or <c>null</c> when exhausted) and the additional references.</returns>
|
||||
Task<(byte[]? ContinuationPoint, ReferenceDescriptionCollection References)> BrowseNextAsync(
|
||||
byte[] continuationPoint, CancellationToken ct = default);
|
||||
|
||||
@@ -91,6 +95,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node to inspect for child objects or variables.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the child lookup.</param>
|
||||
/// <returns><c>true</c> when the node has at least one forward hierarchical child reference; otherwise <c>false</c>.</returns>
|
||||
Task<bool> HasChildrenAsync(NodeId nodeId, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -101,6 +106,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// <param name="endTime">The inclusive end of the requested history window.</param>
|
||||
/// <param name="maxValues">The maximum number of raw samples to return to the client.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the history read.</param>
|
||||
/// <returns>The raw historical data values for the requested window.</returns>
|
||||
Task<IReadOnlyList<DataValue>> HistoryReadRawAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
|
||||
int maxValues, CancellationToken ct = default);
|
||||
|
||||
@@ -113,6 +119,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// <param name="aggregateId">The OPC UA aggregate function to evaluate over the history window.</param>
|
||||
/// <param name="intervalMs">The processing interval, in milliseconds, for each aggregate bucket.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the aggregate history read.</param>
|
||||
/// <returns>The processed/aggregate data values for the requested window.</returns>
|
||||
Task<IReadOnlyList<DataValue>> HistoryReadAggregateAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
|
||||
NodeId aggregateId, double intervalMs, CancellationToken ct = default);
|
||||
|
||||
@@ -121,6 +128,7 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="publishingIntervalMs">The requested publishing interval for monitored items on the new subscription.</param>
|
||||
/// <param name="ct">The cancellation token that aborts subscription creation.</param>
|
||||
/// <returns>The newly created subscription adapter.</returns>
|
||||
Task<ISubscriptionAdapter> CreateSubscriptionAsync(int publishingIntervalMs, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -130,11 +138,13 @@ internal interface ISessionAdapter : IDisposable
|
||||
/// <param name="methodId">The method node to invoke.</param>
|
||||
/// <param name="inputArguments">The ordered input arguments supplied to the server method call.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the method invocation.</param>
|
||||
/// <returns>The output arguments returned by the method call.</returns>
|
||||
Task<IList<object>?> CallMethodAsync(NodeId objectId, NodeId methodId, object[] inputArguments, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Closes the underlying session gracefully before the adapter is disposed or replaced during failover.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts the close request.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task CloseAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ internal interface ISubscriptionAdapter : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="clientHandle">The client handle returned when the monitored item was created.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the monitored-item removal.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task RemoveMonitoredItemAsync(uint clientHandle, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -46,11 +47,13 @@ internal interface ISubscriptionAdapter : IDisposable
|
||||
/// Requests a condition refresh for this subscription.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts the condition refresh request.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task ConditionRefreshAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Removes all monitored items and deletes the subscription.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts subscription deletion.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task DeleteAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ namespace ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the canonical under-LocalAppData folder for the shared OPC UA client's PKI
|
||||
/// store + persisted settings. Renamed from <c>LmxOpcUaClient</c> to <c>OtOpcUaClient</c>
|
||||
/// in task #208; a one-shot migration shim moves a pre-rename folder in place on first
|
||||
/// store + persisted settings. Renamed from <c>LmxOpcUaClient</c> to <c>OtOpcUaClient</c>;
|
||||
/// a one-shot migration shim moves a pre-rename folder in place on first
|
||||
/// resolution so existing developer boxes keep their trusted server certs + saved
|
||||
/// connection settings on upgrade.
|
||||
/// </summary>
|
||||
@@ -14,10 +14,10 @@ namespace ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||
/// </remarks>
|
||||
public static class ClientStoragePaths
|
||||
{
|
||||
/// <summary>Canonical client folder name. Post-#208.</summary>
|
||||
/// <summary>Canonical client folder name.</summary>
|
||||
public const string CanonicalFolderName = "OtOpcUaClient";
|
||||
|
||||
/// <summary>Pre-#208 folder name. Used only by the migration shim.</summary>
|
||||
/// <summary>Legacy folder name, used only by the migration shim.</summary>
|
||||
public const string LegacyFolderName = "LmxOpcUaClient";
|
||||
|
||||
private static readonly Lock _migrationLock = new();
|
||||
@@ -28,6 +28,7 @@ public static class ClientStoragePaths
|
||||
/// one-shot legacy-folder migration before returning so callers that depend on this
|
||||
/// path (PKI store, settings file) find their existing state at the canonical name.
|
||||
/// </summary>
|
||||
/// <returns>The absolute path to the client's canonical top-level folder.</returns>
|
||||
public static string GetRoot()
|
||||
{
|
||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
@@ -37,6 +38,7 @@ public static class ClientStoragePaths
|
||||
}
|
||||
|
||||
/// <summary>Subfolder for the application's PKI store — used by both CLI + UI.</summary>
|
||||
/// <returns>The absolute path to the client's PKI store folder.</returns>
|
||||
public static string GetPkiPath() => Path.Combine(GetRoot(), "pki");
|
||||
|
||||
/// <summary>
|
||||
@@ -45,6 +47,7 @@ public static class ClientStoragePaths
|
||||
/// folder existed + was moved to canonical, false when no migration was needed or
|
||||
/// canonical was already present.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> when a legacy folder existed and was moved to canonical; otherwise <c>false</c>.</returns>
|
||||
public static bool TryRunLegacyMigration()
|
||||
{
|
||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
|
||||
@@ -24,12 +24,14 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="settings">The endpoint, security, and authentication settings used to establish the session.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the connect workflow.</param>
|
||||
/// <returns>The connection metadata for the newly established session.</returns>
|
||||
Task<ConnectionInfo> ConnectAsync(ConnectionSettings settings, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects from the active OPC UA endpoint and tears down subscriptions owned by the client.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts disconnect cleanup.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task DisconnectAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -37,6 +39,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node whose value should be retrieved.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the read request.</param>
|
||||
/// <returns>The current data value of the node.</returns>
|
||||
Task<DataValue> ReadValueAsync(NodeId nodeId, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -45,6 +48,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// <param name="nodeId">The node whose value should be updated.</param>
|
||||
/// <param name="value">The raw value supplied by the CLI or UI workflow.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the write request.</param>
|
||||
/// <returns>The status code returned by the server for the write.</returns>
|
||||
Task<StatusCode> WriteValueAsync(NodeId nodeId, object value, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -52,6 +56,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="parentNodeId">The node to browse, or <see cref="ObjectIds.ObjectsFolder"/> when omitted.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the browse request.</param>
|
||||
/// <returns>The child nodes discovered under <paramref name="parentNodeId"/>.</returns>
|
||||
Task<IReadOnlyList<BrowseResult>> BrowseAsync(NodeId? parentNodeId = null, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -60,6 +65,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// <param name="nodeId">The node whose value changes should be monitored.</param>
|
||||
/// <param name="intervalMs">The monitored-item sampling and publishing interval in milliseconds.</param>
|
||||
/// <param name="ct">The cancellation token that aborts subscription creation.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task SubscribeAsync(NodeId nodeId, int intervalMs = 1000, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -67,6 +73,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node whose live-data subscription should be removed.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the unsubscribe request.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task UnsubscribeAsync(NodeId nodeId, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -75,18 +82,21 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// <param name="sourceNodeId">The event source to monitor, or the server object when omitted.</param>
|
||||
/// <param name="intervalMs">The publishing interval in milliseconds for the alarm subscription.</param>
|
||||
/// <param name="ct">The cancellation token that aborts alarm subscription creation.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task SubscribeAlarmsAsync(NodeId? sourceNodeId = null, int intervalMs = 1000, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the active alarm subscription.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts alarm subscription cleanup.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task UnsubscribeAlarmsAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Requests retained alarm conditions again so a client can repopulate its alarm list after reconnecting.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts the condition refresh request.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task RequestConditionRefreshAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -169,6 +179,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// <param name="endTime">The inclusive end of the requested history range.</param>
|
||||
/// <param name="maxValues">The maximum number of raw values to return.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the history read.</param>
|
||||
/// <returns>The raw historical samples in the requested range, up to <paramref name="maxValues"/>.</returns>
|
||||
Task<IReadOnlyList<DataValue>> HistoryReadRawAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
|
||||
int maxValues = 1000, CancellationToken ct = default);
|
||||
|
||||
@@ -181,6 +192,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// <param name="aggregate">The aggregate function the operator selected for processed history.</param>
|
||||
/// <param name="intervalMs">The processing interval, in milliseconds, for each aggregate bucket.</param>
|
||||
/// <param name="ct">The cancellation token that aborts the processed history request.</param>
|
||||
/// <returns>The aggregated historical values for each processing interval in the requested range.</returns>
|
||||
Task<IReadOnlyList<DataValue>> HistoryReadAggregateAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
|
||||
AggregateType aggregate, double intervalMs = 3600000, CancellationToken ct = default);
|
||||
|
||||
@@ -188,6 +200,7 @@ public interface IOpcUaClientService : IDisposable
|
||||
/// Reads redundancy status data such as redundancy mode, service level, and partner endpoint URIs.
|
||||
/// </summary>
|
||||
/// <param name="ct">The cancellation token that aborts redundancy inspection.</param>
|
||||
/// <returns>The current redundancy status of the connected server.</returns>
|
||||
Task<RedundancyInfo> GetRedundancyInfoAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -24,7 +24,6 @@ public sealed class OpcUaClientService : IOpcUaClientService
|
||||
// Serialises SubscribeAlarmsAsync / UnsubscribeAlarmsAsync so concurrent callers
|
||||
// cannot both pass the _alarmSubscription == null check and create duplicate event
|
||||
// subscriptions. Capacity 1 = at most one waiter; async-friendly (no thread-block).
|
||||
// (Client.Shared-013)
|
||||
private readonly SemaphoreSlim _alarmSubscribeSemaphore = new(1, 1);
|
||||
|
||||
// Track active data subscriptions for replay after failover
|
||||
@@ -137,7 +136,7 @@ public sealed class OpcUaClientService : IOpcUaClientService
|
||||
var endpointUrl = _session?.EndpointUrl ?? _settings?.EndpointUrl ?? string.Empty;
|
||||
|
||||
// Snapshot the subscription adapter references under the lock so a concurrent
|
||||
// RunFailoverAsync that nulls _dataSubscription / _alarmSubscription (Client.Shared-012)
|
||||
// RunFailoverAsync that nulls _dataSubscription / _alarmSubscription
|
||||
// cannot invalidate the references between the null-check and the DeleteAsync call.
|
||||
ISubscriptionAdapter? dataSubscription;
|
||||
ISubscriptionAdapter? alarmSubscription;
|
||||
@@ -303,7 +302,7 @@ public sealed class OpcUaClientService : IOpcUaClientService
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotConnected();
|
||||
|
||||
// Serialise check-and-create under the semaphore (Client.Shared-013): concurrent
|
||||
// Serialise check-and-create under the semaphore: concurrent
|
||||
// callers cannot both pass the null-check and create duplicate alarm subscriptions.
|
||||
// The semaphore is async-friendly; the subscription I/O runs inside the critical section.
|
||||
await _alarmSubscribeSemaphore.WaitAsync(ct);
|
||||
|
||||
@@ -5,8 +5,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.Shared;
|
||||
/// </summary>
|
||||
public sealed class OpcUaClientServiceFactory : IOpcUaClientServiceFactory
|
||||
{
|
||||
/// <summary>Creates a new OPC UA client service instance with production adapters.</summary>
|
||||
/// <returns>A new OpcUaClientService instance.</returns>
|
||||
/// <inheritdoc />
|
||||
public IOpcUaClientService Create()
|
||||
{
|
||||
return new OpcUaClientService();
|
||||
|
||||
@@ -7,8 +7,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||
/// </summary>
|
||||
public sealed class AvaloniaUiDispatcher : IUiDispatcher
|
||||
{
|
||||
/// <summary>Posts an action to the Avalonia UI thread for execution.</summary>
|
||||
/// <param name="action">The action to execute on the UI thread.</param>
|
||||
/// <inheritdoc />
|
||||
public void Post(Action action)
|
||||
{
|
||||
Dispatcher.UIThread.Post(action);
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||
public interface ISettingsService
|
||||
{
|
||||
/// <summary>Loads user settings from persistent storage.</summary>
|
||||
/// <returns>The loaded user settings.</returns>
|
||||
UserSettings Load();
|
||||
/// <summary>Saves user settings to persistent storage.</summary>
|
||||
/// <param name="settings">The settings to save.</param>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||
/// </summary>
|
||||
public sealed class JsonSettingsService : ISettingsService
|
||||
{
|
||||
// ClientStoragePaths.GetRoot runs the one-shot legacy-folder migration so pre-#208
|
||||
// ClientStoragePaths.GetRoot runs the one-shot legacy-folder migration so pre-rename
|
||||
// developer boxes pick up their existing settings.json on first launch post-rename.
|
||||
private static readonly string SettingsDir = ClientStoragePaths.GetRoot();
|
||||
|
||||
@@ -19,8 +19,8 @@ public sealed class JsonSettingsService : ISettingsService
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
/// <summary>Loads user settings from the settings file.</summary>
|
||||
/// <returns>The loaded user settings, or a new default instance if load fails.</returns>
|
||||
/// <inheritdoc />
|
||||
// Returns a new default instance when the settings file is missing or fails to load/parse.
|
||||
public UserSettings Load()
|
||||
{
|
||||
try
|
||||
@@ -37,8 +37,7 @@ public sealed class JsonSettingsService : ISettingsService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Saves user settings to the settings file.</summary>
|
||||
/// <param name="settings">The user settings to save.</param>
|
||||
/// <inheritdoc />
|
||||
public void Save(UserSettings settings)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -6,8 +6,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.UI.Services;
|
||||
/// </summary>
|
||||
public sealed class SynchronousUiDispatcher : IUiDispatcher
|
||||
{
|
||||
/// <summary>Executes the action synchronously on the calling thread.</summary>
|
||||
/// <param name="action">The action to execute.</param>
|
||||
/// <inheritdoc />
|
||||
public void Post(Action action)
|
||||
{
|
||||
action();
|
||||
|
||||
@@ -256,6 +256,7 @@ public partial class AlarmsViewModel : ObservableObject
|
||||
/// <summary>
|
||||
/// Returns the monitored node ID for persistence, or null if not subscribed.
|
||||
/// </summary>
|
||||
/// <returns>The monitored node ID, or null if not subscribed.</returns>
|
||||
public string? GetAlarmSourceNodeId()
|
||||
{
|
||||
return IsSubscribed ? MonitoredNodeIdText : null;
|
||||
|
||||
@@ -30,6 +30,7 @@ public class BrowseTreeViewModel : ObservableObject
|
||||
/// <summary>
|
||||
/// Loads root nodes by browsing with a null parent.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task LoadRootsAsync()
|
||||
{
|
||||
var results = await _service.BrowseAsync();
|
||||
|
||||
@@ -143,6 +143,7 @@ public partial class SubscriptionsViewModel : ObservableObject
|
||||
/// </summary>
|
||||
/// <param name="nodeIdStr">The node ID to subscribe to from the browse tree or persisted settings.</param>
|
||||
/// <param name="intervalMs">The monitored-item interval, in milliseconds, for the subscription.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task AddSubscriptionForNodeAsync(string nodeIdStr, int intervalMs = 1000)
|
||||
{
|
||||
if (!IsConnected || string.IsNullOrWhiteSpace(nodeIdStr)) return;
|
||||
@@ -176,6 +177,7 @@ public partial class SubscriptionsViewModel : ObservableObject
|
||||
/// <param name="nodeIdStr">The root node whose variables should be subscribed recursively.</param>
|
||||
/// <param name="nodeClass">The node class of the starting node so variables can be subscribed immediately.</param>
|
||||
/// <param name="intervalMs">The monitored-item interval, in milliseconds, used for created subscriptions.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public Task AddSubscriptionRecursiveAsync(string nodeIdStr, string nodeClass, int intervalMs = 1000)
|
||||
{
|
||||
return AddSubscriptionRecursiveAsync(nodeIdStr, nodeClass, intervalMs, maxDepth: 10, currentDepth: 0);
|
||||
@@ -211,6 +213,7 @@ public partial class SubscriptionsViewModel : ObservableObject
|
||||
/// <summary>
|
||||
/// Returns the node IDs of all active subscriptions for persistence.
|
||||
/// </summary>
|
||||
/// <returns>The node IDs of all currently active subscriptions.</returns>
|
||||
public List<string> GetSubscribedNodeIds()
|
||||
{
|
||||
return ActiveSubscriptions.Select(s => s.NodeId).ToList();
|
||||
@@ -220,6 +223,7 @@ public partial class SubscriptionsViewModel : ObservableObject
|
||||
/// Restores subscriptions from a saved list of node IDs.
|
||||
/// </summary>
|
||||
/// <param name="nodeIds">The node IDs persisted from a prior UI session.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task RestoreSubscriptionsAsync(IEnumerable<string> nodeIds)
|
||||
{
|
||||
foreach (var nodeId in nodeIds)
|
||||
@@ -232,6 +236,7 @@ public partial class SubscriptionsViewModel : ObservableObject
|
||||
/// </summary>
|
||||
/// <param name="nodeIdStr">The node ID the operator wants to write.</param>
|
||||
/// <param name="rawValue">The raw text value entered by the operator.</param>
|
||||
/// <returns>A tuple indicating whether the write succeeded and a human-readable status message.</returns>
|
||||
public async Task<(bool Success, string Message)> ValidateAndWriteAsync(string nodeIdStr, string rawValue)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -20,6 +20,8 @@ public partial class ShelveAlarmWindow : Window
|
||||
}
|
||||
|
||||
/// <summary>Creates the shelve dialog for an alarm.</summary>
|
||||
/// <param name="alarmsVm">The view model used to issue the shelve/unshelve command.</param>
|
||||
/// <param name="alarm">The alarm event being shelved.</param>
|
||||
public ShelveAlarmWindow(AlarmsViewModel alarmsVm, AlarmEventViewModel alarm)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Reference in New Issue
Block a user