160 lines
5.5 KiB
C#
160 lines
5.5 KiB
C#
using System.Text.Json;
|
|
|
|
namespace Watcher.Services;
|
|
|
|
public class UpdateCheckService : BackgroundService
|
|
{
|
|
private readonly ILogger<UpdateCheckService> _logger;
|
|
private readonly IUpdateCheckStore _updateCheckStore;
|
|
private readonly IVersionService _versionService;
|
|
private readonly string _repositoryUrl;
|
|
private readonly int _checkIntervalHours;
|
|
private readonly bool _enabled;
|
|
private readonly HttpClient _httpClient;
|
|
|
|
public UpdateCheckService(
|
|
ILogger<UpdateCheckService> logger,
|
|
IUpdateCheckStore updateCheckStore,
|
|
IVersionService versionService,
|
|
IConfiguration configuration)
|
|
{
|
|
_logger = logger;
|
|
_updateCheckStore = updateCheckStore;
|
|
_versionService = versionService;
|
|
_httpClient = new HttpClient();
|
|
|
|
// Konfiguration aus Environment Variablen laden
|
|
_repositoryUrl = configuration["UpdateCheck:RepositoryUrl"]
|
|
?? Environment.GetEnvironmentVariable("UPDATE_CHECK_REPOSITORY_URL")
|
|
?? "https://git.triggermeelmo.com/api/v1/repos/Watcher/watcher/releases/latest";
|
|
|
|
_checkIntervalHours = int.TryParse(
|
|
configuration["UpdateCheck:CheckIntervalHours"]
|
|
?? Environment.GetEnvironmentVariable("UPDATE_CHECK_INTERVAL_HOURS"),
|
|
out var hours) ? hours : 24; // Default: 24 Stunden
|
|
|
|
_enabled = bool.TryParse(
|
|
configuration["UpdateCheck:Enabled"]
|
|
?? Environment.GetEnvironmentVariable("UPDATE_CHECK_ENABLED"),
|
|
out var enabled) ? enabled : true; // Default: aktiviert
|
|
|
|
_logger.LogInformation(
|
|
"UpdateCheckService konfiguriert: Enabled={Enabled}, Repository={Repo}, IntervalHours={Hours}",
|
|
_enabled, _repositoryUrl, _checkIntervalHours);
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
if (!_enabled)
|
|
{
|
|
_logger.LogInformation("UpdateCheckService ist deaktiviert.");
|
|
return;
|
|
}
|
|
|
|
// Warte 2 Minuten nach Start, bevor der erste Check läuft
|
|
await Task.Delay(TimeSpan.FromMinutes(2), stoppingToken);
|
|
|
|
var timer = new PeriodicTimer(TimeSpan.FromHours(_checkIntervalHours));
|
|
|
|
while (await timer.WaitForNextTickAsync(stoppingToken))
|
|
{
|
|
try
|
|
{
|
|
await CheckForUpdatesAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Fehler beim Update-Check.");
|
|
}
|
|
|
|
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
|
|
}
|
|
}
|
|
|
|
private async Task CheckForUpdatesAsync()
|
|
{
|
|
var currentVersion = _versionService.GetVersion();
|
|
|
|
_logger.LogInformation("Starte Update-Check. Aktuelle Version: {Version}", currentVersion);
|
|
|
|
// Bei "development" oder "latest" immer als aktuell markieren
|
|
if (currentVersion == "development" || currentVersion == "latest")
|
|
{
|
|
_updateCheckStore.IsUpdateAvailable = false;
|
|
_updateCheckStore.LatestVersion = currentVersion;
|
|
_updateCheckStore.LastChecked = DateTime.UtcNow;
|
|
_logger.LogInformation("Development/Latest Build - keine Update-Prüfung nötig.");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Gitea API abfragen
|
|
var response = await _httpClient.GetAsync(_repositoryUrl);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
_logger.LogWarning("Gitea API Fehler: {StatusCode}", response.StatusCode);
|
|
return;
|
|
}
|
|
|
|
var jsonContent = await response.Content.ReadAsStringAsync();
|
|
var releaseInfo = JsonSerializer.Deserialize<GiteaReleaseResponse>(jsonContent);
|
|
|
|
if (releaseInfo?.TagName == null)
|
|
{
|
|
_logger.LogWarning("Keine Release-Information gefunden.");
|
|
return;
|
|
}
|
|
|
|
var latestVersion = releaseInfo.TagName;
|
|
_updateCheckStore.LatestVersion = latestVersion;
|
|
_updateCheckStore.LastChecked = DateTime.UtcNow;
|
|
|
|
// Versionsvergleich
|
|
var isNewer = CompareVersions(latestVersion, currentVersion);
|
|
_updateCheckStore.IsUpdateAvailable = isNewer;
|
|
|
|
if (isNewer)
|
|
{
|
|
_logger.LogInformation(
|
|
"Neue Version verfügbar: {Latest} (aktuell: {Current})",
|
|
latestVersion, currentVersion);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation(
|
|
"System ist auf dem neuesten Stand: {Version}",
|
|
currentVersion);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Fehler beim Abrufen der Release-Informationen von Gitea.");
|
|
}
|
|
}
|
|
|
|
private bool CompareVersions(string latestVersion, string currentVersion)
|
|
{
|
|
// Entferne "v" Prefix falls vorhanden
|
|
latestVersion = latestVersion.TrimStart('v');
|
|
currentVersion = currentVersion.TrimStart('v');
|
|
|
|
// Versuche semantic versioning zu parsen
|
|
if (Version.TryParse(latestVersion, out var latest) &&
|
|
Version.TryParse(currentVersion, out var current))
|
|
{
|
|
return latest > current;
|
|
}
|
|
|
|
// Fallback: String-Vergleich
|
|
return string.Compare(latestVersion, currentVersion, StringComparison.Ordinal) > 0;
|
|
}
|
|
|
|
// DTO für Gitea API Response
|
|
private class GiteaReleaseResponse
|
|
{
|
|
public string? TagName { get; set; }
|
|
}
|
|
}
|