using System.Text.Json; using System.Text.Json.Serialization; namespace AIStudio.Tools.DataBackup; /// /// The format of a backup: a ZIP file which holds the data folder below DATA_ROOT and the /// configuration folder below CONFIG_ROOT, each in the layout AI Studio keeps on the disk, and the /// manifest as its last entry. /// /// /// What goes in follows DataBackupContents. The paths below the roots are the relative paths of /// that list, so restoring a backup is unpacking it. The manifest comes last: an archive which lacks /// it was not written completely. /// public static class DataBackupFormat { /// /// The version of the format this version of AI Studio writes. A restore refuses a backup of a /// later version, since it cannot know what such a backup holds. /// public const int FORMAT_VERSION = 1; /// /// The file extension of a backup, named like the one of plugin archives. /// public const string FILE_EXTENSION = ".mwbackup"; /// /// The manifest, the last entry of every backup. /// public const string MANIFEST_ENTRY_NAME = "manifest.json"; /// /// Where the data folder lies within a backup. /// public const string DATA_ROOT = "data/"; /// /// Where the configuration folder lies within a backup. /// public const string CONFIG_ROOT = "config/"; /// /// The directory in the data folder where the copies of the vector stores wait while a backup runs. /// The runtime creates it; keep the name in sync with BACKUP_STAGING_DIRECTORY there. /// public const string STAGING_DIRECTORY = ".backup-staging/"; /// /// How the manifest and the plan of a restore are written: readable for anybody who opens them, /// and for the runtime, which applies the plan. /// public static readonly JsonSerializerOptions JSON_OPTIONS = new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, Converters = { new JsonStringEnumConverter() }, }; /// /// File types which are compressed already. Compressing them once more costs time and makes the /// backup no smaller. /// public static readonly IReadOnlySet ALREADY_COMPRESSED_EXTENSIONS = new HashSet(StringComparer.OrdinalIgnoreCase) { ".jpg", ".jpeg", ".png", ".gif", ".webp", ".heic", ".tiff", ".mp3", ".m4a", ".m4b", ".aac", ".ogg", ".opus", ".flac", ".wma", ".mp4", ".m4v", ".mov", ".mkv", ".webm", ".avi", ".wmv", ".flv", ".zip", ".7z", ".gz", ".bz2", ".xz", ".rar", ".pdf", ".docx", ".xlsx", ".pptx", ".odt", ".odp", ".mwplugin", FILE_EXTENSION, }; /// /// The name of the entry which holds a file of the data or configuration folder. /// /// The folder of the file. /// The path of the file within its folder, with forward slashes. /// The name of the entry. public static string EntryName(DataBackupLocation location, string relativePath) => location switch { DataBackupLocation.CONFIG_DIRECTORY => CONFIG_ROOT + relativePath, _ => DATA_ROOT + relativePath, }; }