KI shit haha

This commit is contained in:
2025-11-05 21:15:10 +01:00
parent 8e8bfaee45
commit cfb97536ca
50 changed files with 906 additions and 5029 deletions

View File

@@ -0,0 +1,8 @@
namespace Watcher.Services;
public interface IUpdateCheckStore
{
bool IsUpdateAvailable { get; set; }
string? LatestVersion { get; set; }
DateTime LastChecked { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Watcher.Services;
public interface IVersionService
{
string GetVersion();
}

View File

@@ -0,0 +1,127 @@
using Microsoft.EntityFrameworkCore;
using Watcher.Data;
namespace Watcher.Services;
public class MetricCleanupService : BackgroundService
{
private readonly ILogger<MetricCleanupService> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly int _retentionDays;
private readonly int _checkIntervalHours;
private readonly bool _enabled;
public MetricCleanupService(
ILogger<MetricCleanupService> logger,
IServiceProvider serviceProvider,
IConfiguration configuration)
{
_logger = logger;
_serviceProvider = serviceProvider;
// Konfiguration aus Environment Variablen laden
_retentionDays = int.TryParse(
configuration["DataRetention:MetricRetentionDays"] ??
Environment.GetEnvironmentVariable("METRIC_RETENTION_DAYS"),
out var days) ? days : 30; // Default: 30 Tage
_checkIntervalHours = int.TryParse(
configuration["DataRetention:CleanupIntervalHours"] ??
Environment.GetEnvironmentVariable("METRIC_CLEANUP_INTERVAL_HOURS"),
out var hours) ? hours : 24; // Default: 24 Stunden
_enabled = bool.TryParse(
configuration["DataRetention:Enabled"] ??
Environment.GetEnvironmentVariable("METRIC_CLEANUP_ENABLED"),
out var enabled) ? enabled : true; // Default: aktiviert
_logger.LogInformation(
"MetricCleanupService konfiguriert: Enabled={Enabled}, RetentionDays={Days}, IntervalHours={Hours}",
_enabled, _retentionDays, _checkIntervalHours);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
if (!_enabled)
{
_logger.LogInformation("MetricCleanupService ist deaktiviert.");
return;
}
// Warte 1 Minute nach Start, bevor der erste Cleanup läuft
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
var timer = new PeriodicTimer(TimeSpan.FromHours(_checkIntervalHours));
while (await timer.WaitForNextTickAsync(stoppingToken))
{
try
{
await CleanupOldMetricsAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Fehler beim Cleanup alter Metriken.");
}
// Offset nach Cleanup
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
}
}
private async Task CleanupOldMetricsAsync()
{
_logger.LogInformation("Starte Metric Cleanup für Daten älter als {Days} Tage...", _retentionDays);
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var cutoffDate = DateTime.UtcNow.AddDays(-_retentionDays);
try
{
// Anzahl der zu löschenden Einträge ermitteln
var countToDelete = await context.Metrics
.Where(m => m.Timestamp < cutoffDate)
.CountAsync();
if (countToDelete == 0)
{
_logger.LogInformation("Keine alten Metriken zum Löschen gefunden.");
return;
}
_logger.LogInformation("Lösche {Count} Metriken vor {Date}...", countToDelete, cutoffDate);
// Metriken löschen
var deletedCount = await context.Metrics
.Where(m => m.Timestamp < cutoffDate)
.ExecuteDeleteAsync();
_logger.LogInformation(
"Metric Cleanup abgeschlossen: {DeletedCount} Einträge gelöscht.",
deletedCount);
// Optional: ContainerMetrics auch bereinigen
var containerMetricsCount = await context.ContainerMetrics
.Where(cm => cm.Timestamp < cutoffDate)
.CountAsync();
if (containerMetricsCount > 0)
{
var deletedContainerMetrics = await context.ContainerMetrics
.Where(cm => cm.Timestamp < cutoffDate)
.ExecuteDeleteAsync();
_logger.LogInformation(
"ContainerMetrics Cleanup: {DeletedCount} Einträge gelöscht.",
deletedContainerMetrics);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Fehler beim Löschen alter Metriken aus der Datenbank.");
throw;
}
}
}

View File

@@ -0,0 +1,159 @@
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; }
}
}

View File

@@ -0,0 +1,8 @@
namespace Watcher.Services;
public class UpdateCheckStore : IUpdateCheckStore
{
public bool IsUpdateAvailable { get; set; } = false;
public string? LatestVersion { get; set; } = null;
public DateTime LastChecked { get; set; } = DateTime.MinValue;
}

View File

@@ -0,0 +1,19 @@
namespace Watcher.Services;
public class VersionService : IVersionService
{
private readonly string _version;
public VersionService(IConfiguration configuration)
{
// Priorität: Environment Variable > Configuration > Default
_version = Environment.GetEnvironmentVariable("WATCHER_VERSION")
?? configuration["Application:Version"]
?? "development";
}
public string GetVersion()
{
return _version;
}
}