From e6f9f91bb325fd32e6e1f22f4037d8623fd1fe02 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 28 May 2026 12:12:29 -0400 Subject: [PATCH] feat(comm): route BrowseOpcUaNodeCommand from central to site DCL manager Wires the OPC UA Tag Browser cross-cluster path: central UI Asks via CommunicationService.BrowseOpcUaNodeAsync -> ClusterClient -> site SiteCommunicationActor -> /user/dcl-manager (Task 10 handler). Uses ActorSelection.Tell(msg, Sender) since DataConnectionManagerActor is not a child of DeploymentManagerActor and ActorSelection has no Forward() helper; preserving Sender keeps the BrowseOpcUaNodeResult routing back to the original Ask. Integration test deferred: tests/ZB.MOM.WW.ScadaBridge.IntegrationTests has no ClusterFixture (only ScadaBridgeWebApplicationFactory, which does not expose a Communication service nor a seeded site OPC UA connection). Round-trip will be exercised manually under Task 19. --- .../Actors/SiteCommunicationActor.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/SiteCommunicationActor.cs b/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/SiteCommunicationActor.cs index 728302a3..d83beabf 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/SiteCommunicationActor.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/SiteCommunicationActor.cs @@ -10,6 +10,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health; using ZB.MOM.WW.ScadaBridge.Commons.Messages.InboundApi; using ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration; using ZB.MOM.WW.ScadaBridge.Commons.Messages.Lifecycle; +using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management; using ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification; using ZB.MOM.WW.ScadaBridge.Commons.Messages.RemoteQuery; @@ -144,6 +145,24 @@ public class SiteCommunicationActor : ReceiveActor, IWithTimers Receive(msg => _deploymentManagerProxy.Forward(msg)); Receive(msg => _deploymentManagerProxy.Forward(msg)); + // OPC UA Tag Browser (interactive design-time query) — forward to the + // site-local Data Connection Manager actor, which owns the in-memory + // map of live data-connection adapters keyed by ConnectionName and + // executes the browse against the appropriate OPC UA client. The + // manager is not a child of DeploymentManagerActor, so we route via + // ActorSelection rather than the _deploymentManagerProxy field; the + // path matches the registration in AkkaHostedService. ActorSelection + // has no Forward() helper, so we Tell with the original Sender so the + // BrowseOpcUaNodeResult routes straight back to the central UI's Ask + // (via the CentralCommunicationActor sender chain), not to us. + Receive(msg => + { + _log.Debug( + "Routing BrowseOpcUaNodeCommand for connection '{0}' to DataConnectionManager", + msg.ConnectionName); + Context.ActorSelection("/user/dcl-manager").Tell(msg, Sender); + }); + // Pattern 7: Remote Queries Receive(msg => {