146 lines
4.3 KiB
C#
146 lines
4.3 KiB
C#
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using Duempelkas.App.Services;
|
|
using Microsoft.Data.Sqlite;
|
|
|
|
namespace Duempelkas.Infrastructure.Services;
|
|
|
|
public class BackupService : IBackupService
|
|
{
|
|
private static readonly string DbPath = Path.Combine(
|
|
Path.GetDirectoryName(Environment.ProcessPath ?? AppContext.BaseDirectory) ?? AppContext.BaseDirectory,
|
|
"duempelkas.db");
|
|
|
|
public async Task<string> CreateBackupAsync()
|
|
{
|
|
if (!File.Exists(DbPath))
|
|
{
|
|
return "Keine Datenbankdatei gefunden.";
|
|
}
|
|
|
|
var suggestedFileName = $"duempelkas-backup-{DateTime.Now:yyMMdd-HHmm}.bak";
|
|
var backupPath = await ShowSaveDialogAsync(suggestedFileName);
|
|
|
|
if (string.IsNullOrWhiteSpace(backupPath))
|
|
{
|
|
return "Backup wurde abgebrochen.";
|
|
}
|
|
|
|
backupPath = Path.ChangeExtension(backupPath, ".bak");
|
|
|
|
try
|
|
{
|
|
File.Copy(DbPath, backupPath, overwrite: true);
|
|
return $"Backup gespeichert: {backupPath}";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return $"Backup fehlgeschlagen: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
public async Task<string> RestoreBackupAsync()
|
|
{
|
|
var backupPath = await ShowOpenDialogAsync();
|
|
if (string.IsNullOrWhiteSpace(backupPath))
|
|
{
|
|
return "Wiederherstellung wurde abgebrochen.";
|
|
}
|
|
|
|
if (!File.Exists(backupPath))
|
|
{
|
|
return "Die gewählte Backup-Datei wurde nicht gefunden.";
|
|
}
|
|
|
|
try
|
|
{
|
|
// Ensure no pooled connection keeps stale handles to the previous DB file.
|
|
SqliteConnection.ClearAllPools();
|
|
|
|
var targetDirectory = Path.GetDirectoryName(DbPath);
|
|
if (!string.IsNullOrWhiteSpace(targetDirectory))
|
|
{
|
|
Directory.CreateDirectory(targetDirectory);
|
|
}
|
|
|
|
File.Copy(backupPath, DbPath, overwrite: true);
|
|
SqliteConnection.ClearAllPools();
|
|
return "Wiederherstellung erfolgreich. Die Datenbank wurde neu geladen.";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return $"Wiederherstellung fehlgeschlagen: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
private static Task<string?> ShowSaveDialogAsync(string suggestedFileName)
|
|
{
|
|
return Task.Run(() =>
|
|
{
|
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
|
return Path.Combine(documentsPath, suggestedFileName);
|
|
}
|
|
|
|
var script = $@"
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
$dialog = New-Object System.Windows.Forms.SaveFileDialog
|
|
$dialog.Filter = 'Backup-Dateien (*.bak)|*.bak'
|
|
$dialog.DefaultExt = 'bak'
|
|
$dialog.AddExtension = $true
|
|
$dialog.OverwritePrompt = $true
|
|
$dialog.FileName = '{suggestedFileName.Replace("'", "''")}'
|
|
$dialog.Title = 'Backup speichern'
|
|
if ($dialog.ShowDialog() -eq 'OK') {{ $dialog.FileName }} else {{ '' }}
|
|
";
|
|
|
|
return RunPowerShellDialog(script);
|
|
});
|
|
}
|
|
|
|
private static Task<string?> ShowOpenDialogAsync()
|
|
{
|
|
return Task.Run(() =>
|
|
{
|
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var script = @"
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
$dialog = New-Object System.Windows.Forms.OpenFileDialog
|
|
$dialog.Filter = 'Backup-Dateien (*.bak)|*.bak'
|
|
$dialog.Multiselect = $false
|
|
$dialog.Title = 'Backup auswählen'
|
|
if ($dialog.ShowDialog() -eq 'OK') { $dialog.FileName } else { '' }
|
|
";
|
|
|
|
return RunPowerShellDialog(script);
|
|
});
|
|
}
|
|
|
|
private static string? RunPowerShellDialog(string script)
|
|
{
|
|
var psi = new ProcessStartInfo
|
|
{
|
|
FileName = "powershell",
|
|
Arguments = $"-NoProfile -Command \"{script.Replace("\"", "\\\"") }\"",
|
|
RedirectStandardOutput = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true
|
|
};
|
|
|
|
using var process = Process.Start(psi);
|
|
if (process == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var result = process.StandardOutput.ReadToEnd().Trim();
|
|
process.WaitForExit();
|
|
|
|
return string.IsNullOrWhiteSpace(result) ? null : result;
|
|
}
|
|
} |