using Cleanuparr.Infrastructure.Logging; using Cleanuparr.Persistence; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace Cleanuparr.Infrastructure.Hubs; /// /// Unified SignalR hub for logs and events /// public class AppHub : Hub { private readonly EventsContext _context; private readonly ILogger _logger; private readonly SignalRLogSink _logSink; public AppHub(EventsContext context, ILogger logger, SignalRLogSink logSink) { _context = context; _logger = logger; _logSink = logSink; } /// /// Client requests recent logs /// public async Task GetRecentLogs() { try { var logs = _logSink.GetRecentLogs(); await Clients.Caller.SendAsync("LogsReceived", logs); _logger.LogDebug("Sent {count} recent logs to client {connectionId}", logs.Count(), Context.ConnectionId); } catch (Exception ex) { _logger.LogError(ex, "Failed to send recent logs to client {connectionId}", Context.ConnectionId); } } /// /// Client requests recent events /// public async Task GetRecentEvents(int count = 10) { try { var events = await _context.Events .OrderByDescending(e => e.Timestamp) .Take(Math.Min(count, 100)) // Cap at 100 .ToListAsync(); await Clients.Caller.SendAsync("EventsReceived", events); _logger.LogDebug("Sent {count} recent events to client {connectionId}", events.Count, Context.ConnectionId); } catch (Exception ex) { _logger.LogError(ex, "Failed to send recent events to client {connectionId}", Context.ConnectionId); } } /// /// Client connection established /// public override async Task OnConnectedAsync() { _logger.LogTrace("Client connected to AppHub: {ConnectionId}", Context.ConnectionId); await base.OnConnectedAsync(); } /// /// Client disconnected /// public override async Task OnDisconnectedAsync(Exception? exception) { _logger.LogTrace("Client disconnected from AppHub: {ConnectionId}", Context.ConnectionId); await base.OnDisconnectedAsync(exception); } }