Merge pull request #242 from Moonlight-Panel/AddNewBackupFormat

Added new backup format
This commit is contained in:
Marcel Baumgartner 2023-08-02 22:05:39 +02:00 committed by GitHub
commit 606085c012
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 127 additions and 51 deletions

View file

@ -0,0 +1,119 @@
using System.Diagnostics;
using System.IO.Compression;
using Microsoft.EntityFrameworkCore;
using Moonlight.App.Database;
using Moonlight.App.Services;
using MySql.Data.MySqlClient;
namespace Moonlight.App.Helpers;
public class BackupHelper
{
public async Task CreateBackup(string path)
{
Logger.Info("Started moonlight backup creation");
Logger.Info($"This backup will be saved to '{path}'");
var stopWatch = new Stopwatch();
stopWatch.Start();
var cachePath = PathBuilder.Dir("storage", "backups", "cache");
Directory.CreateDirectory(cachePath);
//
// Exporting database
//
Logger.Info("Exporting database");
var configService = new ConfigService(new());
var dataContext = new DataContext(configService);
await using MySqlConnection conn = new MySqlConnection(dataContext.Database.GetConnectionString());
await using MySqlCommand cmd = new MySqlCommand();
using MySqlBackup mb = new MySqlBackup(cmd);
cmd.Connection = conn;
await conn.OpenAsync();
mb.ExportToFile(PathBuilder.File(cachePath, "database.sql"));
await conn.CloseAsync();
//
// Saving config
//
Logger.Info("Saving configuration");
File.Copy(
PathBuilder.File("storage", "configs", "config.json"),
PathBuilder.File(cachePath, "config.json"));
//
// Saving all storage items needed to restore the panel
//
Logger.Info("Saving resources");
CopyDirectory(
PathBuilder.Dir("storage", "resources"),
PathBuilder.Dir(cachePath, "resources"));
Logger.Info("Saving logs");
CopyDirectory(
PathBuilder.Dir("storage", "logs"),
PathBuilder.Dir(cachePath, "logs"));
Logger.Info("Saving uploads");
CopyDirectory(
PathBuilder.Dir("storage", "uploads"),
PathBuilder.Dir(cachePath, "uploads"));
//
// Compressing the backup to a single file
//
Logger.Info("Compressing");
ZipFile.CreateFromDirectory(cachePath,
path,
CompressionLevel.Fastest,
false);
Directory.Delete(cachePath, true);
stopWatch.Stop();
Logger.Info($"Backup successfully created. Took {stopWatch.Elapsed.TotalSeconds} seconds");
}
private void CopyDirectory(string sourceDirName, string destDirName, bool copySubDirs = true)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException($"Source directory does not exist or could not be found: {sourceDirName}");
}
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string tempPath = Path.Combine(destDirName, file.Name);
file.CopyTo(tempPath, false);
}
if (copySubDirs)
{
DirectoryInfo[] dirs = dir.GetDirectories();
foreach (DirectoryInfo subdir in dirs)
{
string tempPath = Path.Combine(destDirName, subdir.Name);
CopyDirectory(subdir.FullName, tempPath, copySubDirs);
}
}
}
}

View file

@ -44,8 +44,10 @@ public class DatabaseCheckupService
if (migrations.Any())
{
Logger.Info($"{migrations.Length} migrations pending. Updating now");
await BackupDatabase();
var backupHelper = new BackupHelper();
await backupHelper.CreateBackup(
PathBuilder.File("storage", "backups", $"{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds()}.zip"));
Logger.Info("Applying migrations");
@ -58,53 +60,4 @@ public class DatabaseCheckupService
Logger.Info("Database is up-to-date. No migrations have been performed");
}
}
public async Task BackupDatabase()
{
Logger.Info("Creating backup from database");
var configService = new ConfigService(new StorageService());
var dateTimeService = new DateTimeService();
var config = configService.Get().Moonlight.Database;
var connectionString = $"host={config.Host};" +
$"port={config.Port};" +
$"database={config.Database};" +
$"uid={config.Username};" +
$"pwd={config.Password}";
string file = PathBuilder.File("storage", "backups", $"{dateTimeService.GetCurrentUnix()}-mysql.sql");
Logger.Info($"Saving it to: {file}");
Logger.Info("Starting backup...");
try
{
var sw = new Stopwatch();
sw.Start();
await using MySqlConnection conn = new MySqlConnection(connectionString);
await using MySqlCommand cmd = new MySqlCommand();
using MySqlBackup mb = new MySqlBackup(cmd);
cmd.Connection = conn;
await conn.OpenAsync();
mb.ExportToFile(file);
await conn.CloseAsync();
sw.Stop();
Logger.Info($"Done. {sw.Elapsed.TotalSeconds}s");
}
catch (Exception e)
{
Logger.Fatal("-----------------------------------------------");
Logger.Fatal("Unable to create backup for moonlight database");
Logger.Fatal("Moonlight will start anyways in 30 seconds");
Logger.Fatal("-----------------------------------------------");
Logger.Fatal(e);
Thread.Sleep(TimeSpan.FromSeconds(30));
}
}
}

View file

@ -109,6 +109,10 @@ namespace Moonlight
await databaseCheckupService.Perform();
var backupHelper = new BackupHelper();
await backupHelper.CreateBackup(PathBuilder.File("storage", "backups",
$"{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds()}.zip"));
var builder = WebApplication.CreateBuilder(args);
var pluginService = new PluginService();