using Application.Abstractions.Hub; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; namespace Infrastructure.Hubs; internal sealed class ChannelStatusBroadcaster( ILogger logger, IHubContext? hub = null ) : IChannelStatusBroadcaster { public async Task BroadcastAsync(string channelSID, bool isLive, int viewerCount, string? videoId, CancellationToken ct = default) { if (hub is null) { logger.LogWarning("[ChannelStatus] hub is null — broadcast skipped: SID={SID}, isLive={IsLive}", channelSID, isLive); return; } logger.LogInformation("[ChannelStatus] Broadcast → SID={SID}, isLive={IsLive}, viewers={Viewers}, videoId={VideoId}", channelSID, isLive, viewerCount, videoId); // 그룹 기반 fan-out — 사이드바/WatchView 가 AppHub.JoinChannel(channelSID) 로 가입한 클라이언트만 수신 // 이전 Clients.All 은 30초 주기에서 모든 접속자에게 N(채널)×M(사용자) fan-out 발생 await hub.Clients.Group($"channel:{channelSID}").ReceiveChannelStatus(new { channelSID, isLive, viewerCount, videoId }); } }