1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 09:32:55 +08:00

refactor based on reviews

removed LegacyExportManager

Separated the method of CreateZip method and the default export method
This commit is contained in:
cdwcgt 2022-11-21 18:58:01 +09:00
parent ed53168267
commit e37d30a373
No known key found for this signature in database
GPG Key ID: 144396D01095C3A2
10 changed files with 113 additions and 184 deletions

View File

@ -14,7 +14,6 @@ using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.IO;
using osu.Game.Overlays.Notifications;
using osu.Game.Skinning;
using SharpCompress.Archives.Zip;
@ -122,7 +121,7 @@ namespace osu.Game.Tests.Skins.IO
await import1.PerformRead(async s =>
{
await new LegacySkinExporter(osu.Dependencies.Get<Storage>(), osu.Dependencies.Get<RealmAccess>(), new ProgressNotification(), exportStream).ExportAsync(s);
await new LegacySkinExporter(osu.Dependencies.Get<Storage>(), osu.Dependencies.Get<RealmAccess>()).ExportToStreamAsync(s, exportStream);
});
string exportFilename = import1.GetDisplayString();
@ -204,7 +203,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType());
await new LegacySkinExporter(osu.Dependencies.Get<Storage>(), osu.Dependencies.Get<RealmAccess>(), new ProgressNotification(), exportStream).ExportAsync(s);
await new LegacySkinExporter(osu.Dependencies.Get<Storage>(), osu.Dependencies.Get<RealmAccess>()).ExportToStreamAsync(s, exportStream);
Assert.Greater(exportStream.Length, 0);
});
@ -237,7 +236,7 @@ namespace osu.Game.Tests.Skins.IO
Assert.IsFalse(s.Protected);
Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType());
await new LegacySkinExporter(osu.Dependencies.Get<Storage>(), osu.Dependencies.Get<RealmAccess>(), new ProgressNotification(), exportStream).ExportAsync(s);
await new LegacySkinExporter(osu.Dependencies.Get<Storage>(), osu.Dependencies.Get<RealmAccess>()).ExportToStreamAsync(s, exportStream);
Assert.Greater(exportStream.Length, 0);
});

View File

@ -1,20 +1,19 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.IO;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Overlays.Notifications;
using osu.Game.Overlays;
namespace osu.Game.Database
{
public class LegacyBeatmapExporter : LegacyModelExporter<BeatmapSetInfo>
{
protected override string FileExtension => ".osz";
public LegacyBeatmapExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
: base(storage, realm, notification, stream)
public LegacyBeatmapExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
: base(storage, realm, notifications)
{
}
protected override string FileExtension => ".osz";
}
}

View File

@ -1,65 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.IO;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Scoring;
using osu.Game.Skinning;
namespace osu.Game.Database
{
/// <summary>
/// A class which centrally manage legacy file exports.
/// </summary>
[ExcludeFromDynamicCompile]
public class LegacyExportManager : Component
{
[Resolved]
private RealmAccess realmAccess { get; set; } = null!;
[Resolved]
private Storage exportStorage { get; set; } = null!;
[Resolved]
private INotificationOverlay? notifications { get; set; }
/// <summary>
/// Identify the model type and and automatically assigned to the corresponding exporter.
/// </summary>
/// <param name="item">The model should export.</param>
/// <param name="stream">The stream if requires a specific output-stream</param>
/// <returns></returns>
public async Task ExportAsync(IHasGuidPrimaryKey item, Stream? stream = null)
{
var notification = new ProgressNotification
{
State = ProgressNotificationState.Active,
Text = "Exporting...",
CompletionText = "Export completed"
};
notifications?.Post(notification);
switch (item)
{
case SkinInfo:
await new LegacySkinExporter(exportStorage, realmAccess, notification, stream).ExportAsync(item);
break;
case ScoreInfo:
await new LegacyScoreExporter(exportStorage, realmAccess, notification, stream).ExportASync(item);
break;
case BeatmapSetInfo:
await new LegacyBeatmapExporter(exportStorage, realmAccess, notification, stream).ExportAsync(item);
break;
}
}
}
}

View File

@ -5,8 +5,10 @@ using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Graphics;
using osu.Framework.Platform;
using osu.Game.Extensions;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using Realms;
using SharpCompress.Archives.Zip;
@ -16,112 +18,106 @@ namespace osu.Game.Database
/// <summary>
/// A class which handles exporting legacy user data of a single type from osu-stable.
/// </summary>
public abstract class LegacyModelExporter<TModel>
where TModel : RealmObject
public abstract class LegacyModelExporter<TModel> : Component
where TModel : RealmObject, IHasNamedFiles, IHasGuidPrimaryKey
{
/// <summary>
/// The file extension for exports (including the leading '.').
/// </summary>
protected abstract string FileExtension { get; }
protected readonly Storage UserFileStorage;
protected Storage UserFileStorage;
protected Storage ExportStorage;
protected readonly Storage ExportStorage;
protected RealmAccess RealmAccess;
protected readonly RealmAccess RealmAccess;
protected readonly ProgressNotification Notification;
private readonly ProgressNotification notification;
protected string Filename = null!;
protected Stream? OutputStream;
private bool canCancel = true;
protected bool ShouldDisposeStream;
protected LegacyModelExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
protected LegacyModelExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
{
ExportStorage = storage.GetStorageForDirectory(@"exports");
UserFileStorage = storage.GetStorageForDirectory(@"files");
Notification = notification;
RealmAccess = realm;
OutputStream = stream;
ShouldDisposeStream = false;
notification = new ProgressNotification
{
State = ProgressNotificationState.Active,
Text = "Exporting...",
CompletionText = "Export completed"
};
notification.CancelRequested += () => canCancel;
notifications?.Post(notification);
}
/// <summary>
/// Export model to <see cref="OutputStream"/>
/// if <see cref="OutputStream"/> is null, model will export to default folder.
/// </summary>
/// <param name="uuid">The model which have Guid.</param>
/// <returns></returns>
public async Task ExportAsync(RealmObject item)
{
bool canCancel = true;
Notification.CancelRequested += () => canCancel;
if (item is TModel model)
{
Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
public virtual async Task ExportAsync(IHasGuidPrimaryKey uuid)
using (var stream = ExportStorage.CreateFileSafely(Filename))
{
await ExportToStreamAsync(model, stream);
}
}
}
public virtual async Task ExportToStreamAsync(TModel uuid, Stream stream)
{
Guid id = uuid.ID;
await Task.Run(() =>
{
RealmAccess.Run(r =>
{
if (r.Find<TModel>(id) is IHasNamedFiles model)
{
Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
}
else
{
return;
}
if (OutputStream == null)
{
OutputStream = ExportStorage.CreateFileSafely(Filename);
ShouldDisposeStream = true;
}
using (var archive = ZipArchive.Create())
{
float i = 0;
foreach (var file in model.Files)
{
if (Notification.CancellationToken.IsCancellationRequested) return;
archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
i++;
Notification.Progress = i / model.Files.Count();
Notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
}
Notification.Text = "Saving Zip Archive...";
canCancel = false;
archive.SaveTo(OutputStream);
}
TModel model = r.Find<TModel>(id);
createZipArchive(model, stream);
});
}).ContinueWith(OnComplete);
}
private void createZipArchive(TModel model, Stream outputStream)
{
using (var archive = ZipArchive.Create())
{
float i = 0;
foreach (var file in model.Files)
{
if (notification.CancellationToken.IsCancellationRequested) return;
archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath()));
i++;
notification.Progress = i / model.Files.Count();
notification.Text = $"Exporting... ({i}/{model.Files.Count()})";
}
notification.Text = "Saving Zip Archive...";
canCancel = false;
archive.SaveTo(outputStream);
}
}
protected void OnComplete(Task t)
{
if (ShouldDisposeStream)
{
OutputStream?.Dispose();
}
if (t.IsFaulted)
{
Notification.State = ProgressNotificationState.Cancelled;
notification.State = ProgressNotificationState.Cancelled;
return;
}
if (Notification.CancellationToken.IsCancellationRequested)
if (notification.CancellationToken.IsCancellationRequested)
{
return;
}
Notification.CompletionText = "Export Complete, Click to open the folder";
Notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(Filename);
Notification.State = ProgressNotificationState.Completed;
notification.CompletionText = "Export Complete, Click to open the folder";
notification.CompletionClickAction += () => ExportStorage.PresentFileExternally(Filename);
notification.State = ProgressNotificationState.Completed;
}
}
}

View File

@ -6,49 +6,36 @@ using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Game.Extensions;
using osu.Game.Overlays.Notifications;
using osu.Game.Overlays;
using osu.Game.Scoring;
namespace osu.Game.Database
{
public class LegacyScoreExporter : LegacyModelExporter<ScoreInfo>
{
protected override string FileExtension => ".osr";
public LegacyScoreExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
: base(storage, realm, notification, stream)
public LegacyScoreExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
: base(storage, realm, notifications)
{
}
public override async Task ExportASync(IHasGuidPrimaryKey uuid)
protected override string FileExtension => ".osr";
public override async Task ExportToStreamAsync(ScoreInfo uuid, Stream stream)
{
await Task.Run(() =>
{
RealmAccess.Run(r =>
{
if (r.Find<ScoreInfo>(uuid.ID) is IHasNamedFiles model)
{
Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
}
else
{
return;
}
ScoreInfo model = r.Find<ScoreInfo>(uuid.ID);
Filename = $"{model.GetDisplayString().GetValidFilename()}{FileExtension}";
var file = model.Files.SingleOrDefault();
if (file == null)
return;
if (Notification.CancellationToken.IsCancellationRequested) return;
if (OutputStream == null)
{
OutputStream = ExportStorage.CreateFileSafely(Filename);
ShouldDisposeStream = true;
}
using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
inputStream.CopyTo(OutputStream);
inputStream.CopyTo(stream);
});
}).ContinueWith(OnComplete);
}

View File

@ -1,20 +1,19 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.IO;
using osu.Framework.Platform;
using osu.Game.Overlays.Notifications;
using osu.Game.Overlays;
using osu.Game.Skinning;
namespace osu.Game.Database
{
public class LegacySkinExporter : LegacyModelExporter<SkinInfo>
{
protected override string FileExtension => ".osk";
public LegacySkinExporter(Storage storage, RealmAccess realm, ProgressNotification notification, Stream? stream = null)
: base(storage, realm, notification, stream)
public LegacySkinExporter(Storage storage, RealmAccess realm, INotificationOverlay? notifications = null)
: base(storage, realm, notifications)
{
}
protected override string FileExtension => ".osk";
}
}

View File

@ -34,6 +34,7 @@ using osuTK.Graphics;
using osu.Game.Online.API;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Utils;
using osu.Framework.Platform;
namespace osu.Game.Online.Leaderboards
{
@ -72,8 +73,14 @@ namespace osu.Game.Online.Leaderboards
[Resolved(canBeNull: true)]
private SongSelect songSelect { get; set; }
[Resolved(canBeNull: true)]
private LegacyExportManager exporter { get; set; }
[Resolved]
private Storage storage { get; set; }
[Resolved]
private RealmAccess realm { get; set; }
[Resolved]
private INotificationOverlay notifications { get; set; }
public ITooltip<ScoreInfo> GetCustomTooltip() => new LeaderboardScoreTooltip();
public virtual ScoreInfo TooltipContent => Score;
@ -427,7 +434,7 @@ namespace osu.Game.Online.Leaderboards
if (Score.Files.Count > 0)
{
items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => exporter?.ExportAsync(Score))));
items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => Task.Run(() => new LegacyScoreExporter(storage, realm, notifications).ExportAsync(Score))));
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
}

View File

@ -126,9 +126,6 @@ namespace osu.Game
[Cached]
private readonly LegacyImportManager legacyImportManager = new LegacyImportManager();
[Cached]
private readonly LegacyExportManager legacyExportManager = new LegacyExportManager();
[Cached]
private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
@ -871,7 +868,6 @@ namespace osu.Game
}), rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(legacyImportManager, Add);
loadComponentSingleFile(legacyExportManager, Add);
loadComponentSingleFile(screenshotManager, Add);

View File

@ -13,6 +13,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
@ -137,8 +138,14 @@ namespace osu.Game.Overlays.Settings.Sections
[Resolved]
private SkinManager skins { get; set; }
[Resolved(canBeNull: true)]
private LegacyExportManager exporter { get; set; }
[Resolved]
private Storage storage { get; set; }
[Resolved]
private RealmAccess realm { get; set; }
[Resolved]
private INotificationOverlay notifications { get; set; }
private Bindable<Skin> currentSkin;
@ -161,7 +168,7 @@ namespace osu.Game.Overlays.Settings.Sections
{
try
{
currentSkin.Value.SkinInfo.PerformRead(s => exporter?.ExportAsync(s));
currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage, realm, notifications).ExportAsync(s));
}
catch (Exception e)
{

View File

@ -21,6 +21,7 @@ using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Threading;
@ -90,6 +91,12 @@ namespace osu.Game.Screens.Edit
[Resolved]
private RulesetStore rulesets { get; set; }
[Resolved]
private Storage storage { get; set; }
[Resolved]
private RealmAccess realm { get; set; }
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
@ -179,9 +186,6 @@ namespace osu.Game.Screens.Edit
private Bindable<float> editorBackgroundDim;
private Bindable<bool> editorHitMarkers;
[Resolved(canBeNull: true)]
private LegacyExportManager exporter { get; set; }
public Editor(EditorLoader loader = null)
{
this.loader = loader;
@ -938,7 +942,7 @@ namespace osu.Game.Screens.Edit
private void exportBeatmap()
{
Save();
Task.Run(() => exporter?.ExportAsync(Beatmap.Value.BeatmapSetInfo));
Task.Run(() => new LegacyBeatmapExporter(storage, realm, notifications).ExportAsync(Beatmap.Value.BeatmapSetInfo));
}
/// <summary>