using Microsoft.AspNetCore.SignalR; using PlotLine.Hubs; namespace PlotLine.Services; public sealed class WordCompanionPresenceMonitor( IWordCompanionPresenceService presence, IHubContext hub) : BackgroundService { protected override async Task ExecuteAsync(CancellationToken stoppingToken) { using var timer = new PeriodicTimer(TimeSpan.FromSeconds(10)); try { while (await timer.WaitForNextTickAsync(stoppingToken)) { var offlineStatuses = await presence.MarkStaleOfflineAsync(); foreach (var status in offlineStatuses) { await hub.Clients .Group(PresenceGroup(status.UserID)) .SendAsync("WordCompanionPresenceChanged", status, stoppingToken); } } } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { } } private static string PresenceGroup(int userId) => $"word-companion-presence:{userId}"; }