using Microsoft.AspNetCore.SignalR; using NexusReader.Application.Abstractions.Messaging; using NexusReader.Infrastructure.RealTime; namespace NexusReader.Infrastructure.RealTime; /// /// SignalR implementation of . /// Uses to push progress updates to all of a user's connected devices. /// internal sealed class SignalRSyncBroadcaster : ISyncBroadcaster { private readonly IHubContext _hubContext; public SignalRSyncBroadcaster(IHubContext hubContext) { _hubContext = hubContext; } /// public async Task BroadcastProgressAsync( string userId, string pageId, DateTime timestamp, string? excludedConnectionId, CancellationToken cancellationToken = default) { // Using Clients.User(userId) targeted broadcasting. // This pushes to all of a user's connected devices across all sessions. if (!string.IsNullOrEmpty(excludedConnectionId)) { await _hubContext.Clients .User(userId) .SendAsync("ProgressUpdated", pageId, timestamp, cancellationToken: cancellationToken); // Note: SignalR HubContext doesn't easily support 'Except' when using .User(id) // from outside the Hub itself without custom IUserIdProvider. // If strict exclusion is needed, we'd use groups, but requirements mandate .User(userId). } else { await _hubContext.Clients .User(userId) .SendAsync("ProgressUpdated", pageId, timestamp, cancellationToken: cancellationToken); } } /// public async Task BroadcastIngestionProgressAsync( string userId, string message, double progress, CancellationToken cancellationToken = default) { // Pushes ingestion status (e.g., "Parsing chapters...") and progress (0.0-1.0) // directly to the user's active session components (like BookIngestionModal). await _hubContext.Clients .User(userId) .SendAsync("IngestionProgress", message, progress, cancellationToken: cancellationToken); } }