using IBKRTrader.Core.Database; using IBKRTrader.Core.Logging; using IBKRTrader.Core.Settings; namespace IBKRTrader.Core.Workers.BuiltIn; /// /// BackupWorker (Core) – läuft alle 30 Minuten (konfigurierbar). /// 1. Ruft mysqldump.exe auf → SQL-Dump in Backups\DB\ /// 2. Kopiert Logs\ → Backups\Logs\ /// Falls mysqldump nicht gefunden: Warnung und Überspringen. /// public class BackupWorker : WorkerBase { private readonly SettingsService _settings; public override string Name => "BackupWorker"; public override string Module => "Core"; public override WorkerType Type => WorkerType.Worker; protected override TimeSpan? Interval => TimeSpan.FromMinutes(_settings.Settings.WorkerSettings.BackupWorker.IntervalMinutes); public BackupWorker(LoggingService logger, DatabaseService db, SettingsService settings) : base(logger, db) { _settings = settings; Info.Active = settings.Settings.WorkerSettings.BackupWorker.Enabled; } protected override async Task ExecuteAsync(CancellationToken ct) { var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm"); var backupRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Backups"); var dbDir = Path.Combine(backupRoot, "DB"); var logsDir = Path.Combine(backupRoot, "Logs"); Directory.CreateDirectory(dbDir); Directory.CreateDirectory(logsDir); // ── 1. Datenbank-Dump ──────────────────────────────────────────────── await RunMysqlDumpAsync(dbDir, timestamp, ct); // ── 2. Logs-Backup ─────────────────────────────────────────────────── CopyLogs(logsDir, timestamp); Logger.Info(Module, $"Backup abgeschlossen: {timestamp}"); } // ─── mysqldump ──────────────────────────────────────────────────────────── private async Task RunMysqlDumpAsync(string dbDir, string timestamp, CancellationToken ct) { var dump = FindMysqldump(); if (dump == null) { Logger.Warn(Module, "mysqldump.exe nicht gefunden – DB-Backup übersprungen."); return; } var db = _settings.Settings.Database; var dumpFile = Path.Combine(dbDir, $"{db.Database}_{timestamp}.sql"); var args = $"--host={db.Host} --port={db.Port} " + $"--user={db.User} --password={db.Password} " + $"--single-transaction --routines --triggers " + $"{db.Database} --result-file=\"{dumpFile}\""; var psi = new System.Diagnostics.ProcessStartInfo { FileName = dump, Arguments = args, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var proc = System.Diagnostics.Process.Start(psi) ?? throw new InvalidOperationException("mysqldump konnte nicht gestartet werden."); await proc.WaitForExitAsync(ct); if (proc.ExitCode != 0) { var err = await proc.StandardError.ReadToEndAsync(ct); Logger.Warn(Module, $"mysqldump Exitcode {proc.ExitCode}: {err}"); } else { Logger.Info(Module, $"DB-Dump erstellt: {Path.GetFileName(dumpFile)}"); } } private static string? FindMysqldump() { // Häufige Installationspfade auf Windows-Server var candidates = new[] { "mysqldump.exe", @"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe", @"C:\Program Files\MySQL\MySQL Server 8.4\bin\mysqldump.exe", @"C:\xampp\mysql\bin\mysqldump.exe" }; foreach (var c in candidates) if (File.Exists(c)) return c; // PATH-Suche var pathVar = Environment.GetEnvironmentVariable("PATH") ?? ""; foreach (var dir in pathVar.Split(';')) { var full = Path.Combine(dir.Trim(), "mysqldump.exe"); if (File.Exists(full)) return full; } return null; } // ─── Logs kopieren ──────────────────────────────────────────────────────── private void CopyLogs(string logsBackupDir, string timestamp) { try { var srcLogs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); if (!Directory.Exists(srcLogs)) return; var destDir = Path.Combine(logsBackupDir, timestamp); CopyDirectory(srcLogs, destDir); Logger.Info(Module, $"Logs-Backup erstellt: {destDir}"); } catch (Exception ex) { Logger.Warn(Module, $"Logs-Backup fehlgeschlagen: {ex.Message}"); } } private static void CopyDirectory(string src, string dest) { Directory.CreateDirectory(dest); foreach (var file in Directory.GetFiles(src)) File.Copy(file, Path.Combine(dest, Path.GetFileName(file)), overwrite: true); foreach (var dir in Directory.GetDirectories(src)) CopyDirectory(dir, Path.Combine(dest, Path.GetFileName(dir))); } }