Files
douyin/service/DatabaseUpgradeBackup.cs

78 lines
3.3 KiB
C#

using System.Reflection;
namespace dy.net.service
{
public sealed class DatabaseUpgradeBackup
{
private readonly string _databaseRoot;
private readonly string _version;
private readonly string _markerPath;
private DatabaseUpgradeBackup(string databaseRoot, string version)
{
_databaseRoot = databaseRoot;
_version = version;
_markerPath = Path.Combine(databaseRoot, ".schema-version");
}
public static DatabaseUpgradeBackup Prepare(string dbPath)
{
var root = string.IsNullOrWhiteSpace(dbPath)
? Path.Combine(Environment.CurrentDirectory, "db")
: Path.Combine(dbPath, "db");
Directory.CreateDirectory(root);
var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? "0.2.24";
var backup = new DatabaseUpgradeBackup(root, version);
backup.CreateIfNeeded();
return backup;
}
public void MarkSchemaReady() => File.WriteAllText(_markerPath, _version);
private void CreateIfNeeded()
{
var database = Path.Combine(_databaseRoot, "dy.sqlite");
if (!File.Exists(database)) return;
if (File.Exists(_markerPath) && string.Equals(File.ReadAllText(_markerPath).Trim(), _version, StringComparison.Ordinal)) return;
var backupRoot = Path.Combine(_databaseRoot, "upgrade-backups");
Directory.CreateDirectory(backupRoot);
var versionPrefix = $"pre-{_version}-";
if (!Directory.EnumerateDirectories(backupRoot, versionPrefix + "*").Any())
{
var destination = Path.Combine(backupRoot, versionPrefix + DateTime.Now.ToString("yyyyMMdd-HHmmss"));
Directory.CreateDirectory(destination);
CopyIfPresent(database, Path.Combine(destination, "dy.sqlite"));
CopyIfPresent(database + "-wal", Path.Combine(destination, "dy.sqlite-wal"));
CopyIfPresent(database + "-shm", Path.Combine(destination, "dy.sqlite-shm"));
CopyDirectory(Path.Combine(_databaseRoot, "keys"), Path.Combine(destination, "keys"));
}
foreach (var old in new DirectoryInfo(backupRoot).GetDirectories()
.OrderByDescending(x => x.CreationTimeUtc).Skip(3))
{
try { old.Delete(true); }
catch (Exception ex) { Serilog.Log.Warning(ex, "清理旧升级备份失败:{Path}", old.FullName); }
}
}
private static void CopyIfPresent(string source, string destination)
{
if (File.Exists(source)) File.Copy(source, destination, false);
}
private static void CopyDirectory(string source, string destination)
{
if (!Directory.Exists(source)) return;
Directory.CreateDirectory(destination);
foreach (var file in Directory.EnumerateFiles(source, "*", SearchOption.AllDirectories))
{
var relative = Path.GetRelativePath(source, file);
var target = Path.Combine(destination, relative);
Directory.CreateDirectory(Path.GetDirectoryName(target)!);
File.Copy(file, target, false);
}
}
}
}