using Microsoft.AspNetCore.SignalR; using ZB.MOM.WW.MxGateway.Contracts.Proto; namespace ZB.MOM.WW.MxGateway.Server.Dashboard.Hubs; /// /// Broadcasts MxEvents to clients subscribed to the /// session's group. Fire-and-forget: we hand the send to the hub context /// and return immediately so the source gRPC stream is never blocked. /// Errors are logged once and dropped — keeping the SignalR mirror best-effort /// preserves the gRPC contract that exists today. /// public sealed class DashboardEventBroadcaster( IHubContext hubContext, ILogger logger) : IDashboardEventBroadcaster { /// Publishes an MX event to connected dashboard clients. /// The session identifier. /// The MX event to publish. public void Publish(string sessionId, MxEvent mxEvent) { if (string.IsNullOrEmpty(sessionId) || mxEvent is null) { return; } Task send = hubContext.Clients .Group(EventsHub.GroupName(sessionId)) .SendAsync(EventsHub.EventMessage, mxEvent); if (!send.IsCompletedSuccessfully) { _ = send.ContinueWith( t => { if (t.Exception is { } ex) { logger.LogDebug(ex, "Dashboard event mirror to session {SessionId} failed.", sessionId); } }, TaskScheduler.Default); } } }