using System.Net.Http.Json; using DataTransfer.Client.Shared; namespace DataTransfer.Client.Services; /// Periodically fetches the load of the relay server; shared by all components of the page. public sealed class ServerStatusMonitor(HttpClient http, ILogger logger) : IDisposable { private static readonly TimeSpan PollInterval = TimeSpan.FromSeconds(5); private readonly CancellationTokenSource _stopping = new(); private Task? _polling; public event Action? Changed; /// The latest status, or null while it is unknown. public ServerStatus? Current { get; private set; } public void EnsureStarted() => _polling ??= PollAsync(_stopping.Token); public async Task RefreshAsync(CancellationToken cancellationToken = default) { ServerStatus? status; try { status = await http.GetFromJsonAsync(TransferProtocol.StatusPath.TrimStart('/'), cancellationToken); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { return; } catch (Exception ex) { logger.LogDebug(ex, "Fetching the server status failed"); status = null; } if (status != Current) { Current = status; Changed?.Invoke(); } } public void Dispose() { _stopping.Cancel(); _stopping.Dispose(); } private async Task PollAsync(CancellationToken cancellationToken) { using var timer = new PeriodicTimer(PollInterval); try { do { await RefreshAsync(cancellationToken); } while (await timer.WaitForNextTickAsync(cancellationToken)); } catch (OperationCanceledException) { } } }