From 20f93c83d694b17f86c0343e86bdf96811796d2e Mon Sep 17 00:00:00 2001 From: naoey Date: Fri, 8 Sep 2017 22:37:28 +0530 Subject: [PATCH] Make downloads happen in BeatmapManager. --- .../Visual/TestCasePlaySongSelect.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 74 ++++++++++++++++++- .../API/Requests/DownloadBeatmapSetRequest.cs | 21 ++++++ osu.Game/OsuGameBase.cs | 14 ++-- osu.Game/Overlays/Direct/DirectPanel.cs | 68 +++-------------- osu.Game/osu.Game.csproj | 1 + 6 files changed, 115 insertions(+), 65 deletions(-) create mode 100644 osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs diff --git a/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs index 379100b543..8d1ae7d913 100644 --- a/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Desktop.Tests/Visual/TestCasePlaySongSelect.cs @@ -32,7 +32,7 @@ namespace osu.Desktop.Tests.Visual backingDatabase.CreateTable(); rulesets = new RulesetStore(backingDatabase); - manager = new BeatmapManager(storage, null, backingDatabase, rulesets); + manager = new BeatmapManager(storage, null, backingDatabase, rulesets, null); for (int i = 0; i < 100; i += 10) manager.Import(createTestBeatmapSet(i)); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 551612330b..fbbc94a8f5 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -20,6 +20,9 @@ using osu.Game.IPC; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using SQLite.Net; +using osu.Game.Online.API.Requests; +using System.Threading.Tasks; +using osu.Game.Online.API; namespace osu.Game.Beatmaps { @@ -63,6 +66,10 @@ namespace osu.Game.Beatmaps private readonly BeatmapStore beatmaps; + private readonly APIAccess api; + + private readonly Dictionary downloadsMap; + // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private BeatmapIPCChannel ipc; @@ -76,7 +83,7 @@ namespace osu.Game.Beatmaps /// public Func GetStableStorage { private get; set; } - public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null) + public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) { beatmaps = new BeatmapStore(connection); beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s); @@ -88,9 +95,12 @@ namespace osu.Game.Beatmaps this.files = files; this.connection = connection; this.rulesets = rulesets; + this.api = api; if (importHost != null) ipc = new BeatmapIPCChannel(importHost, this); + + downloadsMap = new Dictionary(); } /// @@ -177,6 +187,68 @@ namespace osu.Game.Beatmaps beatmaps.Add(beatmapSetInfo); } + /// + /// Download a beatmap + /// + /// The beatmap to be downloaded + public DownloadBeatmapSetRequest Download(BeatmapSetInfo beatmapSetInfo) + { + if (api == null || downloadsMap.ContainsKey(beatmapSetInfo)) return null; + + ProgressNotification downloadNotification = new ProgressNotification + { + Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}", + }; + + var request = new DownloadBeatmapSetRequest(beatmapSetInfo); + + request.DownloadProgressed += progress => + { + downloadNotification.State = ProgressNotificationState.Active; + downloadNotification.Progress = progress; + }; + + request.Success += data => + { + downloadNotification.State = ProgressNotificationState.Completed; + + using (var stream = new MemoryStream(data)) + using (var archive = new OszArchiveReader(stream)) + Import(archive); + + downloadsMap.Remove(beatmapSetInfo); + }; + + request.Failure += data => + { + downloadNotification.State = ProgressNotificationState.Completed; + Logger.Error(data, "Failed to get beatmap download information"); + downloadsMap.Remove(beatmapSetInfo); + }; + + downloadNotification.CancelRequested += () => + { + Logger.Log("Cancel requested"); + downloadsMap.Remove(beatmapSetInfo); + return true; + }; + + downloadsMap[beatmapSetInfo] = request; + PostNotification?.Invoke(downloadNotification); + + // don't run in the main api queue as this is a long-running task. + Task.Run(() => request.Perform(api)); + + return request; + } + + /// + /// Check if a beatmap is already downloading. + /// + /// The to check against. + /// true if a download request already exists, false if it doesn't. + public bool IsDownloading(BeatmapSetInfo beatmap) => downloadsMap.ContainsKey(beatmap); + /// /// Delete a beatmap from the manager. /// Is a no-op for already deleted beatmaps. diff --git a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs new file mode 100644 index 0000000000..28473d9f66 --- /dev/null +++ b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs @@ -0,0 +1,21 @@ +using osu.Game.Beatmaps; +using System; + +namespace osu.Game.Online.API.Requests +{ + public class DownloadBeatmapSetRequest : APIDownloadRequest + { + private readonly BeatmapSetInfo beatmapSet; + + public Action DownloadProgressed; + + public DownloadBeatmapSetRequest(BeatmapSetInfo beatmapSet) + { + this.beatmapSet = beatmapSet; + + Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total); + } + + protected override string Target => $@"beatmapsets/{beatmapSet.OnlineBeatmapSetID}/download"; + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index a7136ce803..76eb7d5101 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -106,9 +106,15 @@ namespace osu.Game connection.CreateTable(); + dependencies.Cache(API = new APIAccess + { + Username = LocalConfig.Get(OsuSetting.Username), + Token = LocalConfig.Get(OsuSetting.Token) + }); + dependencies.Cache(RulesetStore = new RulesetStore(connection)); dependencies.Cache(FileStore = new FileStore(connection, Host.Storage)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, Host)); + dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, API, Host)); dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager, RulesetStore)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(connection, RulesetStore)); dependencies.Cache(new OsuColour()); @@ -144,12 +150,6 @@ namespace osu.Game Beatmap = new NonNullableBindable(defaultBeatmap); BeatmapManager.DefaultBeatmap = defaultBeatmap; - dependencies.Cache(API = new APIAccess - { - Username = LocalConfig.Get(OsuSetting.Username), - Token = LocalConfig.Get(OsuSetting.Token) - }); - Beatmap.ValueChanged += b => { // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index a642f72821..746cd39085 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -115,23 +115,8 @@ namespace osu.Game.Overlays.Direct base.OnHoverLost(state); } - // this should eventually be moved to a more central place, like BeatmapManager. - private DownloadBeatmapSetRequest downloadRequest; - protected void StartDownload() { - if (api == null) return; - - // we already have an active download running. - if (downloadRequest != null) - { - content.MoveToX(-5, 50, Easing.OutSine).Then() - .MoveToX(5, 100, Easing.InOutSine).Then() - .MoveToX(-5, 100, Easing.InOutSine).Then() - .MoveToX(0, 50, Easing.InSine).Then(); - return; - } - if (!api.LocalUser.Value.IsSupporter) { notifications.Post(new SimpleNotification @@ -142,25 +127,28 @@ namespace osu.Game.Overlays.Direct return; } + // we already have an active download running. + if (beatmaps.IsDownloading(SetInfo)) + { + content.MoveToX(-5, 50, Easing.OutSine).Then() + .MoveToX(5, 100, Easing.InOutSine).Then() + .MoveToX(-5, 100, Easing.InOutSine).Then() + .MoveToX(0, 50, Easing.InSine).Then(); + return; + } + + var downloadRequest = beatmaps.Download(SetInfo); + progressBar.FadeIn(400, Easing.OutQuint); progressBar.ResizeHeightTo(4, 400, Easing.OutQuint); progressBar.Current.Value = 0; - ProgressNotification downloadNotification = new ProgressNotification - { - Text = $"Downloading {SetInfo.Metadata.Artist} - {SetInfo.Metadata.Title}", - }; - - downloadRequest = new DownloadBeatmapSetRequest(SetInfo); downloadRequest.Failure += e => { progressBar.Current.Value = 0; progressBar.FadeOut(500); - downloadNotification.State = ProgressNotificationState.Completed; Logger.Error(e, "Failed to get beatmap download information"); - - downloadRequest = null; }; downloadRequest.Progress += (current, total) => @@ -169,45 +157,13 @@ namespace osu.Game.Overlays.Direct progressBar.Current.Value = progress; - downloadNotification.State = ProgressNotificationState.Active; - downloadNotification.Progress = progress; }; downloadRequest.Success += data => { progressBar.Current.Value = 1; progressBar.FadeOut(500); - - downloadNotification.State = ProgressNotificationState.Completed; - - using (var stream = new MemoryStream(data)) - using (var archive = new OszArchiveReader(stream)) - beatmaps.Import(archive); }; - - downloadNotification.CancelRequested += () => - { - downloadRequest.Cancel(); - downloadRequest = null; - return true; - }; - - notifications.Post(downloadNotification); - - // don't run in the main api queue as this is a long-running task. - Task.Run(() => downloadRequest.Perform(api)); - } - - public class DownloadBeatmapSetRequest : APIDownloadRequest - { - private readonly BeatmapSetInfo beatmapSet; - - public DownloadBeatmapSetRequest(BeatmapSetInfo beatmapSet) - { - this.beatmapSet = beatmapSet; - } - - protected override string Target => $@"beatmapsets/{beatmapSet.OnlineBeatmapSetID}/download"; } protected override void LoadComplete() diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 05ba3e25ab..5e1c5426ec 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -98,6 +98,7 @@ +