using Akka.Actor; using Akka.Cluster.Tools.PublishSubscribe; using Akka.Event; using Microsoft.AspNetCore.SignalR; using ZB.MOM.WW.OtOpcUa.Commons.Messages.Logging; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs; /// /// Akka actor that subscribes to the script-logs DistributedPubSub topic and forwards each /// to every SignalR client connected to . /// public sealed class ScriptLogSignalRBridge : ReceiveActor { public const string TopicName = "script-logs"; private readonly IHubContext _hub; private readonly IInProcessBroadcaster _broadcaster; private readonly ILoggingAdapter _log = Context.GetLogger(); /// Creates a Props instance for the ScriptLogSignalRBridge. /// The SignalR hub context for sending messages to clients. /// In-process fan-out read directly by the Blazor Server Script log page. public static Props Props(IHubContext hub, IInProcessBroadcaster broadcaster) => Akka.Actor.Props.Create(() => new ScriptLogSignalRBridge(hub, broadcaster)); /// Initializes a new instance of the class. /// The SignalR hub context for sending messages to clients. /// In-process fan-out read directly by the Blazor Server Script log page. public ScriptLogSignalRBridge(IHubContext hub, IInProcessBroadcaster broadcaster) { _hub = hub; _broadcaster = broadcaster; ReceiveAsync(ForwardAsync); Receive(_ => { /* DPS confirmation */ }); } /// protected override void PreStart() => DistributedPubSub.Get(Context.System).Mediator.Tell(new Subscribe(TopicName, Self)); private async Task ForwardAsync(ScriptLogEntry msg) { // In-process fan-out first — this is what the Blazor Server Script log page reads. The hub // push is kept for any out-of-process (e.g. WASM) SignalR client. _broadcaster.Publish(msg); try { await _hub.Clients.All.SendAsync(ScriptLogHub.MethodName, msg); } catch (Exception ex) { _log.Warning(ex, "ScriptLogSignalRBridge: SignalR push failed for {ScriptId}", msg.ScriptId); } } }