namespace HaCompanion; class StatisticsHolder { public string name; public string url; public string requestPath; public UptimeStatistics? latestResult; } public class UptimePollerService : IHostedService { private readonly int _interval; private Timer _timer; private List _uptimeStatistics = new List(); private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; public UptimePollerService(IConfiguration configuration, IHttpClientFactory httpClientFactory, ILogger logger) { _httpClientFactory = httpClientFactory; _logger = logger; _interval = configuration.GetRequiredSection("Uptime").GetValue("Period") * 60_000; var statsEntries = configuration.GetRequiredSection("Uptime").GetRequiredSection("Websites").GetChildren(); foreach (var entry in statsEntries) { var holder = new StatisticsHolder() { name = entry.GetRequiredSection("website").Value!, url = entry.GetRequiredSection("BaseUrl").Value!, requestPath = entry.GetRequiredSection("RequestUrl").Value!, latestResult = null }; _logger.LogDebug("Added stats entry {Name}", holder.name); _uptimeStatistics.Add(holder); } } public async Task StartAsync(CancellationToken cancellationToken) { _logger.LogDebug("Starting async."); await OnTimerFiredAsync(); _timer = new Timer(async _ => await OnTimerFiredAsync(), null, _interval, Timeout.Infinite); } public Task StopAsync(CancellationToken cancellationToken) { _logger.LogDebug("Stopping async."); _timer?.Dispose(); return Task.CompletedTask; } public List GetUptimeStatistics() { var result = new List(); foreach (var statistics in _uptimeStatistics) { result.Add(statistics.latestResult); } return result; } private async Task OnTimerFiredAsync() { _logger.LogInformation("Executing HTTP status checks."); try { foreach (var holder in _uptimeStatistics) { _logger.LogDebug("{Name} - Checking uptime.", holder.name); try { var client = _httpClientFactory.CreateClient(holder.name); var response = await client.GetAsync(holder.requestPath); if (!response.IsSuccessStatusCode) { holder.latestResult = new UptimeStatistics(holder.name, true, false, null); _logger.LogWarning("{Name} - HTTP failed. Status code: {Code}", holder.name, response.StatusCode); } else { holder.latestResult = new UptimeStatistics(holder.name, true, true, true); _logger.LogDebug("{Name} - HTTP success.", holder.name); } } catch (HttpRequestException he) { holder.latestResult = new UptimeStatistics(holder.name, false, null, null); _logger.LogWarning("{Name} - HTTP failed with HttpRequestException. {Ex}", holder.name, he); } catch (Exception e) { holder.latestResult = new UptimeStatistics(holder.name, false, null, null); _logger.LogError("{Name} - HTTP failed with general Exception. {Ex}", holder.name, e); } } } finally { _logger.LogDebug("HTTP status checks completed."); _timer?.Change(_interval, Timeout.Infinite); } } }