using OTSSignsOrchestrator.Server.Clients; using OTSSignsOrchestrator.Server.Data.Entities; using Microsoft.Extensions.Configuration; namespace OTSSignsOrchestrator.Server.Health.Checks; /// /// Compares the installed Xibo CMS version (from GET /about) against the latest known /// release configured in HealthChecks:LatestXiboVersion. Reports Degraded if behind. /// public sealed class XiboVersionHealthCheck : IHealthCheck { private readonly XiboClientFactory _clientFactory; private readonly IServiceProvider _services; private readonly IConfiguration _configuration; private readonly ILogger _logger; public string CheckName => "XiboVersion"; public bool AutoRemediate => false; public XiboVersionHealthCheck( XiboClientFactory clientFactory, IServiceProvider services, IConfiguration configuration, ILogger logger) { _clientFactory = clientFactory; _services = services; _configuration = configuration; _logger = logger; } public async Task RunAsync(Instance instance, CancellationToken ct) { var latestVersion = _configuration["HealthChecks:LatestXiboVersion"]; if (string.IsNullOrEmpty(latestVersion)) return new HealthCheckResult(HealthStatus.Healthy, "LatestXiboVersion not configured — skipping"); var (client, _) = await ResolveAsync(instance); if (client is null) return new HealthCheckResult(HealthStatus.Critical, "No OAuth app — cannot check version"); try { var response = await client.GetAboutAsync(); if (!response.IsSuccessStatusCode || response.Content is null) return new HealthCheckResult(HealthStatus.Critical, "GET /about failed"); string? installedVersion = null; if (response.Content is System.Text.Json.JsonElement je && je.TryGetProperty("version", out var verProp)) { installedVersion = verProp.GetString(); } if (string.IsNullOrEmpty(installedVersion)) return new HealthCheckResult(HealthStatus.Degraded, "Could not determine installed version"); if (string.Equals(installedVersion, latestVersion, StringComparison.OrdinalIgnoreCase)) return new HealthCheckResult(HealthStatus.Healthy, $"Xibo version {installedVersion} is current"); return new HealthCheckResult(HealthStatus.Degraded, $"Xibo version {installedVersion}, latest is {latestVersion}", "Consider scheduling an upgrade"); } catch (Exception ex) { return new HealthCheckResult(HealthStatus.Critical, $"Version check failed: {ex.Message}"); } } private async Task<(IXiboApiClient? Client, string Abbrev)> ResolveAsync(Instance instance) { var abbrev = instance.Customer.Abbreviation; var oauthApp = instance.OauthAppRegistries.FirstOrDefault(); if (oauthApp is null) return (null, abbrev); var settings = _services.GetRequiredService(); var secret = await settings.GetAsync(Core.Services.SettingsService.InstanceOAuthSecretId(abbrev)); if (string.IsNullOrEmpty(secret)) return (null, abbrev); var client = await _clientFactory.CreateAsync(instance.XiboUrl, oauthApp.ClientId, secret); return (client, abbrev); } }