Added new backup format
This commit is contained in:
119
Moonlight/App/Helpers/BackupHelper.cs
Normal file
119
Moonlight/App/Helpers/BackupHelper.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,9 @@ public class DatabaseCheckupService
|
|||||||
{
|
{
|
||||||
Logger.Info($"{migrations.Length} migrations pending. Updating now");
|
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");
|
Logger.Info("Applying migrations");
|
||||||
|
|
||||||
@@ -58,53 +60,4 @@ public class DatabaseCheckupService
|
|||||||
Logger.Info("Database is up-to-date. No migrations have been performed");
|
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -109,6 +109,10 @@ namespace Moonlight
|
|||||||
|
|
||||||
await databaseCheckupService.Perform();
|
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 builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
var pluginService = new PluginService();
|
var pluginService = new PluginService();
|
||||||
|
|||||||
Reference in New Issue
Block a user