Files

58 lines
1.9 KiB
C#
Raw Permalink Normal View History

using System.Text.Json;
namespace PrivaPub.Infrastructure.Backup
{
// A restore asked for (by the administrator's page or the CLI) and carried out at the next boot, before anything
// else (Program, MaintenanceGate): restore.json in the backups' directory, written whole or not at all.
public sealed class RestoreMarker
{
public const string FileName = "restore.json";
public const int MaxAttempts = 3;
public string Backup { get; set; }//the backup restored
public string PreRestore { get; set; }//the backup taken just before, what the protective merge reads
public string State { get; set; } = "pending";//pending, then running
public string RequestedBy { get; set; }//who asked: a root's name, or "cli"
public int Attempts { get; set; }
public DateTime RequestedAt { get; set; } = DateTime.UtcNow;
public string Error { get; set; }
public static string PathIn(string backupsRoot) => Path.Combine(backupsRoot, FileName);
public static RestoreMarker Read(string backupsRoot)
{
var path = PathIn(backupsRoot);
if (!File.Exists(path))
return default;
try
{
return JsonSerializer.Deserialize<RestoreMarker>(File.ReadAllText(path));
}
catch (JsonException)
{
//never written half (Write is atomic): someone's hand; the server won't guess what was meant
return new RestoreMarker { State = "unreadable", Attempts = MaxAttempts, Error = $"{FileName} can't be read" };
}
}
public void Write(string backupsRoot)
{
Directory.CreateDirectory(backupsRoot);
var path = PathIn(backupsRoot);
var part = path + ".part";
using (var file = new FileStream(part, FileMode.Create, FileAccess.Write))
{
JsonSerializer.Serialize(file, this);
file.Flush(flushToDisk: true);
}
File.Move(part, path, overwrite: true);
}
public static void Clear(string backupsRoot)
{
var path = PathIn(backupsRoot);
if (File.Exists(path))
File.Delete(path);
}
}
}