// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System.IO; using System.Linq; using System.Threading; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.Overlays.Notifications; using Realms; using SharpCompress.Common; using SharpCompress.Writers; using SharpCompress.Writers.Zip; using Logger = osu.Framework.Logging.Logger; namespace osu.Game.Database { /// /// An exporter which handles the common scenario of exporting a model to a zip-based archive, usually with a custom file extension. /// public abstract class LegacyArchiveExporter : LegacyExporter where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey { protected LegacyArchiveExporter(Storage storage) : base(storage) { } public override void ExportToStream(TModel model, Stream outputStream, ProgressNotification? notification, CancellationToken cancellationToken = default) => exportZipArchive(model, outputStream, notification, cancellationToken); /// /// Exports an item to Stream as a legacy (.zip based) package. /// /// The model to be exported. /// The output stream to export to. /// An optional target notification to update with ongoing export progress. /// The cancellation token. private void exportZipArchive(TModel model, Stream outputStream, ProgressNotification? notification, CancellationToken cancellationToken = default) { using (var writer = new ZipWriter(outputStream, new ZipWriterOptions(CompressionType.Deflate))) { int i = 0; int fileCount = model.Files.Count(); bool fileMissing = false; foreach (var file in model.Files) { cancellationToken.ThrowIfCancellationRequested(); using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath())) { if (stream == null) { Logger.Log($"File {file.Filename} is missing in local storage and will not be included in the export", LoggingTarget.Database); fileMissing = true; continue; } writer.Write(file.Filename, stream); } if (notification != null) { notification.Progress = (float)(i + 1) / fileCount; } i++; } if (fileMissing) { Logger.Log("Some of model files are missing, they will not be included in the archive", LoggingTarget.Database, LogLevel.Error); } } } } }