using Microsoft.AspNetCore.SignalR; namespace WiSL.EndPoints.Hubs; // Real-time push for WI Line Digital Twin / Plant Overview / Workstation Display Screen. // Hub is transient; no mutable state stored in instance fields. LoginDTO trust model isn't needed // here since group membership carries no identity/authorization semantics (line/workstation groups // are pure "what am I watching," same tenant-scoping the underlying REST endpoints already enforce // on every fetch) — unlike CollabHub, this hub does not reconstruct or use LoginDTO at all. public class WiHub(ILogger logger) : Hub { public override async Task OnConnectedAsync() { logger.LogInformation("WiHub connected: {ConnectionId}", Context.ConnectionId); await base.OnConnectedAsync(); } public override async Task OnDisconnectedAsync(Exception? exception) { if (exception is not null) logger.LogWarning(exception, "WiHub disconnected with error: {ConnectionId}", Context.ConnectionId); await base.OnDisconnectedAsync(exception); } // ── Hub methods (client-callable) ────────────────────────────────── public Task JoinLineGroup(int productionLineId) => Groups.AddToGroupAsync(Context.ConnectionId, LineGroup(productionLineId)); public Task LeaveLineGroup(int productionLineId) => Groups.RemoveFromGroupAsync(Context.ConnectionId, LineGroup(productionLineId)); public Task JoinWorkstationGroup(int workStationId) => Groups.AddToGroupAsync(Context.ConnectionId, WorkstationGroup(workStationId)); public Task LeaveWorkstationGroup(int workStationId) => Groups.RemoveFromGroupAsync(Context.ConnectionId, WorkstationGroup(workStationId)); // ── Group naming ──────────────────────────────────────────────────── public static string LineGroup(int productionLineId) => $"wi:line:{productionLineId}"; public static string WorkstationGroup(int workStationId) => $"wi:workstation:{workStationId}"; }