using HanaToolbox.Config; using HanaToolbox.Logging; using HanaToolbox.Services.Interfaces; namespace HanaToolbox.Services; /// /// Deletes backup and log files older than their configured retention period. /// Runs as root (no user switching needed for file deletion). /// public sealed class CleanerService(AppLogger logger) : ICleanerService { public Task RunAsync(CleanerConfig config, CancellationToken ct = default) { logger.Step($"Cleaning tenant backup path: {config.TenantBackupPath} " + $"(retention: {config.TenantRetentionDays}d)"); CleanDirectory(config.TenantBackupPath, config.TenantRetentionDays); foreach (var logPath in config.LogBackupPaths) { ct.ThrowIfCancellationRequested(); logger.Step($"Cleaning log backup path: {logPath} " + $"(retention: {config.LogRetentionDays}d)"); CleanDirectory(logPath, config.LogRetentionDays); } logger.Success("Cleanup complete."); return Task.CompletedTask; } private void CleanDirectory(string directory, int retentionDays) { if (!Directory.Exists(directory)) { logger.Warning($"Directory not found, skipping: {directory}"); return; } var cutoff = DateTime.UtcNow.AddDays(-retentionDays); int deleted = 0; try { foreach (var file in Directory.EnumerateFiles(directory, "*", SearchOption.TopDirectoryOnly)) { try { if (File.GetLastWriteTimeUtc(file) < cutoff) { File.Delete(file); deleted++; logger.Info($"Deleted: {file}"); } } catch (Exception ex) { logger.Warning($"Could not delete '{file}': {ex.Message}"); } } } catch (Exception ex) { logger.Error($"Error enumerating '{directory}': {ex.Message}"); } logger.Info($"Deleted {deleted} file(s) from '{directory}'."); } }