Initial commit: IBKRTrader
.NET WinForms-Anwendung (Core, Modules/CongressTrading, UI). Enthaelt .gitignore und settings.example.json als Konfigurationsvorlage. Echte settings.json mit Zugangsdaten ist bewusst ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
using IBKRTrader.Core.Database;
|
||||
using IBKRTrader.Core.Logging;
|
||||
using IBKRTrader.Core.Settings;
|
||||
|
||||
namespace IBKRTrader.Core.Workers.BuiltIn;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user