refactor(browse): rename BrowseOpcUaNode* to protocol-agnostic BrowseNode*
Renames BrowseOpcUaNodeCommand/Result -> BrowseNodeCommand/Result and CommunicationService.BrowseOpcUaNodeAsync -> BrowseNodeAsync across Commons, Communication, SiteRuntime, DCL actors, and CentralUI. Wire manifest name follows (BrowseOpcUaNode -> BrowseNode). Browse regression tests green.
This commit is contained in:
@@ -50,7 +50,7 @@ public static class ServiceCollectionExtensions
|
||||
// Backs the Audit Log page's Export button via GET /api/centralui/audit/export.
|
||||
services.AddScoped<IAuditLogExportService, AuditLogExportService>();
|
||||
|
||||
// OPC UA Tag Browser (Task 14): facade over CommunicationService.BrowseOpcUaNodeAsync
|
||||
// OPC UA Tag Browser (Task 14): facade over CommunicationService.BrowseNodeAsync
|
||||
// that enforces the CentralUI-side Design-role trust boundary and translates
|
||||
// transport failures into typed BrowseFailure results for the dialog.
|
||||
services.AddScoped<IOpcUaBrowseService, OpcUaBrowseService>();
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
/// CentralUI facade over the central-to-site OPC UA browse command. Backs the
|
||||
/// OPC UA Tag Browser dialog: each tree expansion / manual node-id paste calls
|
||||
/// <see cref="BrowseChildrenAsync"/>, which forwards a
|
||||
/// <see cref="BrowseOpcUaNodeCommand"/> to the owning site via
|
||||
/// <see cref="BrowseNodeCommand"/> to the owning site via
|
||||
/// <see cref="ZB.MOM.WW.ScadaBridge.Communication.CommunicationService"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
@@ -29,7 +29,7 @@ public interface IOpcUaBrowseService
|
||||
/// <param name="connectionName">Name of the site-local data connection to browse against — the site's <c>DataConnectionManagerActor</c> indexes its children by name.</param>
|
||||
/// <param name="parentNodeId">Node to browse, or <c>null</c> to browse from the server root.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task<BrowseOpcUaNodeResult> BrowseChildrenAsync(
|
||||
Task<BrowseNodeResult> BrowseChildrenAsync(
|
||||
string siteId,
|
||||
string connectionName,
|
||||
string? parentNodeId,
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Default <see cref="IOpcUaBrowseService"/> implementation — a thin facade over
|
||||
/// <see cref="CommunicationService.BrowseOpcUaNodeAsync"/> that enforces the
|
||||
/// <see cref="CommunicationService.BrowseNodeAsync"/> that enforces the
|
||||
/// CentralUI-side <c>Design</c>-role trust boundary and translates transport
|
||||
/// exceptions into a typed <see cref="BrowseFailure"/> result.
|
||||
/// </summary>
|
||||
@@ -36,7 +36,7 @@ public sealed class OpcUaBrowseService : IOpcUaBrowseService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<BrowseOpcUaNodeResult> BrowseChildrenAsync(
|
||||
public async Task<BrowseNodeResult> BrowseChildrenAsync(
|
||||
string siteId,
|
||||
string connectionName,
|
||||
string? parentNodeId,
|
||||
@@ -47,7 +47,7 @@ public sealed class OpcUaBrowseService : IOpcUaBrowseService
|
||||
var state = await _auth.GetAuthenticationStateAsync();
|
||||
if (!state.User.HasClaim(JwtTokenService.RoleClaimType, "Design"))
|
||||
{
|
||||
return new BrowseOpcUaNodeResult(
|
||||
return new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(BrowseFailureKind.ServerError, "Not authorized."));
|
||||
@@ -55,9 +55,9 @@ public sealed class OpcUaBrowseService : IOpcUaBrowseService
|
||||
|
||||
try
|
||||
{
|
||||
return await _communication.BrowseOpcUaNodeAsync(
|
||||
return await _communication.BrowseNodeAsync(
|
||||
siteId,
|
||||
new BrowseOpcUaNodeCommand(connectionName, parentNodeId),
|
||||
new BrowseNodeCommand(connectionName, parentNodeId),
|
||||
cancellationToken);
|
||||
}
|
||||
catch (TimeoutException ex)
|
||||
@@ -65,7 +65,7 @@ public sealed class OpcUaBrowseService : IOpcUaBrowseService
|
||||
// Akka Ask timed out — the site (or its OPC UA session) didn't answer
|
||||
// within CommunicationOptions.QueryTimeout. Surface as a typed
|
||||
// Timeout failure so the dialog can render an inline banner.
|
||||
return new BrowseOpcUaNodeResult(
|
||||
return new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(BrowseFailureKind.Timeout, ex.Message));
|
||||
@@ -80,7 +80,7 @@ public sealed class OpcUaBrowseService : IOpcUaBrowseService
|
||||
{
|
||||
// Any other transport / serialization failure: keep the dialog
|
||||
// alive and let the user fall back to manual node-id paste.
|
||||
return new BrowseOpcUaNodeResult(
|
||||
return new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(BrowseFailureKind.ServerError, ex.Message));
|
||||
|
||||
@@ -15,11 +15,11 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
|
||||
/// </remarks>
|
||||
/// <param name="ConnectionName">Name of the site-local data connection to browse against.</param>
|
||||
/// <param name="ParentNodeId">Node to browse, or null to browse from the server root (ObjectsFolder).</param>
|
||||
public record BrowseOpcUaNodeCommand(
|
||||
public record BrowseNodeCommand(
|
||||
string ConnectionName,
|
||||
string? ParentNodeId);
|
||||
|
||||
public record BrowseOpcUaNodeResult(
|
||||
public record BrowseNodeResult(
|
||||
IReadOnlyList<BrowseNode> Children,
|
||||
bool Truncated,
|
||||
BrowseFailure? Failure);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Keyed by <see cref="ConnectionName"/> (not id) for the same reason as
|
||||
/// <see cref="BrowseOpcUaNodeCommand"/>: the site-side
|
||||
/// <see cref="BrowseNodeCommand"/>: the site-side
|
||||
/// <c>DataConnectionManagerActor</c> indexes its children by connection name,
|
||||
/// and the central UI already has the connection name in scope from the
|
||||
/// bindings table. The central <c>DataConnections</c> table's id is not
|
||||
|
||||
@@ -152,10 +152,10 @@ public class SiteCommunicationActor : ReceiveActor, IWithTimers
|
||||
// DataConnectionActor children (which own the live OPC UA sessions)
|
||||
// only exist on the singleton's node. The singleton then re-forwards
|
||||
// to its own /user/dcl-manager, which DOES have the connection.
|
||||
Receive<BrowseOpcUaNodeCommand>(msg => _deploymentManagerProxy.Forward(msg));
|
||||
Receive<BrowseNodeCommand>(msg => _deploymentManagerProxy.Forward(msg));
|
||||
|
||||
// Test Bindings (interactive design-time read) — same routing rationale
|
||||
// as BrowseOpcUaNodeCommand above: the singleton always lands on the
|
||||
// as BrowseNodeCommand above: the singleton always lands on the
|
||||
// active site node, which is the node that owns the DataConnectionActor
|
||||
// children holding the live OPC UA sessions.
|
||||
Receive<ReadTagValuesCommand>(msg => _deploymentManagerProxy.Forward(msg));
|
||||
|
||||
@@ -360,13 +360,13 @@ public class CommunicationService
|
||||
/// <param name="command">The OPC UA browse command.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The browse result (children + truncation flag + structured failure).</returns>
|
||||
public Task<BrowseOpcUaNodeResult> BrowseOpcUaNodeAsync(
|
||||
public Task<BrowseNodeResult> BrowseNodeAsync(
|
||||
string siteId,
|
||||
BrowseOpcUaNodeCommand command,
|
||||
BrowseNodeCommand command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var envelope = new SiteEnvelope(siteId, command);
|
||||
return GetActor().Ask<BrowseOpcUaNodeResult>(
|
||||
return GetActor().Ask<BrowseNodeResult>(
|
||||
envelope, _options.QueryTimeout, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ public class CommunicationService
|
||||
/// server backing the given data connection. Used by the CentralUI "Test
|
||||
/// Bindings" dialog on the Configure Instance page. The Ask is bounded by
|
||||
/// <see cref="CommunicationOptions.QueryTimeout"/> — same latency budget
|
||||
/// as <see cref="BrowseOpcUaNodeAsync"/> (both are interactive one-shot
|
||||
/// as <see cref="BrowseNodeAsync"/> (both are interactive one-shot
|
||||
/// design-time queries).
|
||||
/// </summary>
|
||||
/// <param name="siteId">The target site identifier.</param>
|
||||
|
||||
@@ -234,7 +234,7 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
// apply it so its state survives into the next ReSubscribeAll.
|
||||
HandleSubscribeCompleted(sc);
|
||||
break;
|
||||
case BrowseOpcUaNodeCommand browse:
|
||||
case BrowseNodeCommand browse:
|
||||
// Browse is an interactive design-time query; never stash. The
|
||||
// adapter has no session yet in this state, so reply with a
|
||||
// typed ConnectionNotConnected failure so the dialog can render
|
||||
@@ -307,7 +307,7 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
case RetryTagResolution:
|
||||
HandleRetryTagResolution();
|
||||
break;
|
||||
case BrowseOpcUaNodeCommand browse:
|
||||
case BrowseNodeCommand browse:
|
||||
HandleBrowse(browse);
|
||||
break;
|
||||
case ReadTagValuesCommand read:
|
||||
@@ -432,7 +432,7 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
// apply it so its state survives into the next ReSubscribeAll.
|
||||
HandleSubscribeCompleted(sc);
|
||||
break;
|
||||
case BrowseOpcUaNodeCommand browse:
|
||||
case BrowseNodeCommand browse:
|
||||
// Browse is design-time and never stashed. While reconnecting
|
||||
// the adapter has no live session, so the adapter call will
|
||||
// throw ConnectionNotConnectedException — mapped by HandleBrowse.
|
||||
@@ -982,7 +982,7 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
// ── OPC UA Tag Browser (interactive design-time query) ──
|
||||
|
||||
/// <summary>
|
||||
/// Handles a <see cref="BrowseOpcUaNodeCommand"/> forwarded by the
|
||||
/// Handles a <see cref="BrowseNodeCommand"/> forwarded by the
|
||||
/// <see cref="DataConnectionManagerActor"/>. The capability check (does
|
||||
/// this adapter support browsing?) and all browse-failure mapping live
|
||||
/// here because the adapter is held by this actor, not the manager.
|
||||
@@ -999,14 +999,14 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
/// <see cref="HandleWrite"/> — so the captured <see cref="Sender"/> is
|
||||
/// safe to use from the continuation (which runs off the actor thread).
|
||||
/// </summary>
|
||||
private void HandleBrowse(BrowseOpcUaNodeCommand command)
|
||||
private void HandleBrowse(BrowseNodeCommand command)
|
||||
{
|
||||
var sender = Sender;
|
||||
|
||||
if (_adapter is not IBrowsableDataConnection browsable)
|
||||
{
|
||||
_log.Debug("[{0}] Browse requested but adapter does not implement IBrowsableDataConnection", _connectionName);
|
||||
sender.Tell(new BrowseOpcUaNodeResult(
|
||||
sender.Tell(new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(
|
||||
@@ -1021,21 +1021,21 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
||||
{
|
||||
if (t.IsCompletedSuccessfully)
|
||||
{
|
||||
return new BrowseOpcUaNodeResult(t.Result.Children, t.Result.Truncated, Failure: null);
|
||||
return new BrowseNodeResult(t.Result.Children, t.Result.Truncated, Failure: null);
|
||||
}
|
||||
|
||||
var baseEx = t.Exception?.GetBaseException();
|
||||
return baseEx switch
|
||||
{
|
||||
ConnectionNotConnectedException notConnected => new BrowseOpcUaNodeResult(
|
||||
ConnectionNotConnectedException notConnected => new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(BrowseFailureKind.ConnectionNotConnected, notConnected.Message)),
|
||||
OperationCanceledException => new BrowseOpcUaNodeResult(
|
||||
OperationCanceledException => new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(BrowseFailureKind.Timeout, "Browse cancelled.")),
|
||||
_ => new BrowseOpcUaNodeResult(
|
||||
_ => new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(
|
||||
|
||||
@@ -46,7 +46,7 @@ public class DataConnectionManagerActor : ReceiveActor
|
||||
Receive<WriteTagRequest>(HandleRouteWrite);
|
||||
Receive<RemoveConnectionCommand>(HandleRemoveConnection);
|
||||
Receive<GetAllHealthReports>(HandleGetAllHealthReports);
|
||||
Receive<BrowseOpcUaNodeCommand>(HandleBrowse);
|
||||
Receive<BrowseNodeCommand>(HandleBrowse);
|
||||
Receive<ReadTagValuesCommand>(HandleReadTagValues);
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ public class DataConnectionManagerActor : ReceiveActor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Routes a <see cref="BrowseOpcUaNodeCommand"/> from the central UI's OPC UA
|
||||
/// Routes a <see cref="BrowseNodeCommand"/> from the central UI's OPC UA
|
||||
/// Tag Browser to the child <see cref="DataConnectionActor"/> that owns the
|
||||
/// named connection. The manager is the only actor that knows whether a
|
||||
/// connection exists at this site — so it owns the
|
||||
@@ -123,7 +123,7 @@ public class DataConnectionManagerActor : ReceiveActor
|
||||
/// else (capability check, session state, server errors) lives inside the
|
||||
/// child where the adapter is held.
|
||||
/// </summary>
|
||||
private void HandleBrowse(BrowseOpcUaNodeCommand command)
|
||||
private void HandleBrowse(BrowseNodeCommand command)
|
||||
{
|
||||
if (_connectionActors.TryGetValue(command.ConnectionName, out var actor))
|
||||
{
|
||||
@@ -132,7 +132,7 @@ public class DataConnectionManagerActor : ReceiveActor
|
||||
else
|
||||
{
|
||||
_log.Warning("No connection actor for {0} during browse", command.ConnectionName);
|
||||
Sender.Tell(new BrowseOpcUaNodeResult(
|
||||
Sender.Tell(new BrowseNodeResult(
|
||||
Array.Empty<BrowseNode>(),
|
||||
Truncated: false,
|
||||
new BrowseFailure(
|
||||
|
||||
@@ -149,12 +149,12 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
|
||||
Receive<RouteToSetAttributesRequest>(RouteInboundApiSetAttributes);
|
||||
|
||||
// OPC UA Tag Browser — singleton-only re-forward to local /user/dcl-manager.
|
||||
// BrowseOpcUaNodeCommand is routed to this singleton (active node) by
|
||||
// BrowseNodeCommand is routed to this singleton (active node) by
|
||||
// SiteCommunicationActor so the dcl-manager we forward to is guaranteed
|
||||
// to be the one holding the live DataConnectionActor children. ActorSelection
|
||||
// has no Forward() extension in this Akka.NET version, so we Tell with the
|
||||
// original Sender preserved (semantically identical to Forward).
|
||||
Receive<BrowseOpcUaNodeCommand>(msg =>
|
||||
Receive<BrowseNodeCommand>(msg =>
|
||||
Context.ActorSelection("/user/dcl-manager").Tell(msg, Sender));
|
||||
|
||||
// Test Bindings — same singleton-only re-forward as the browse handler
|
||||
|
||||
Reference in New Issue
Block a user