Make downloads happen in BeatmapManager.

This commit is contained in:
naoey 2017-09-08 22:37:28 +05:30
parent 4dc67ed796
commit 20f93c83d6
No known key found for this signature in database
GPG Key ID: 2CCE71F6713C9069
6 changed files with 115 additions and 65 deletions

View File

@ -32,7 +32,7 @@ namespace osu.Desktop.Tests.Visual
backingDatabase.CreateTable<StoreVersion>(); backingDatabase.CreateTable<StoreVersion>();
rulesets = new RulesetStore(backingDatabase); 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) for (int i = 0; i < 100; i += 10)
manager.Import(createTestBeatmapSet(i)); manager.Import(createTestBeatmapSet(i));

View File

@ -20,6 +20,9 @@ using osu.Game.IPC;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using SQLite.Net; using SQLite.Net;
using osu.Game.Online.API.Requests;
using System.Threading.Tasks;
using osu.Game.Online.API;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
@ -63,6 +66,10 @@ namespace osu.Game.Beatmaps
private readonly BeatmapStore beatmaps; private readonly BeatmapStore beatmaps;
private readonly APIAccess api;
private readonly Dictionary<BeatmapSetInfo, DownloadBeatmapSetRequest> downloadsMap;
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private BeatmapIPCChannel ipc; private BeatmapIPCChannel ipc;
@ -76,7 +83,7 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
public Func<Storage> GetStableStorage { private get; set; } public Func<Storage> 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 = new BeatmapStore(connection);
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s); beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
@ -88,9 +95,12 @@ namespace osu.Game.Beatmaps
this.files = files; this.files = files;
this.connection = connection; this.connection = connection;
this.rulesets = rulesets; this.rulesets = rulesets;
this.api = api;
if (importHost != null) if (importHost != null)
ipc = new BeatmapIPCChannel(importHost, this); ipc = new BeatmapIPCChannel(importHost, this);
downloadsMap = new Dictionary<BeatmapSetInfo, DownloadBeatmapSetRequest>();
} }
/// <summary> /// <summary>
@ -177,6 +187,68 @@ namespace osu.Game.Beatmaps
beatmaps.Add(beatmapSetInfo); beatmaps.Add(beatmapSetInfo);
} }
/// <summary>
/// Download a beatmap
/// </summary>
/// <param name="beatmapSetInfo">The beatmap to be downloaded</param>
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;
}
/// <summary>
/// Check if a beatmap is already downloading.
/// </summary>
/// <param name="beatmap">The <see cref="BeatmapSetInfo"/>to check against.</param>
/// <returns>true if a download request already exists, false if it doesn't.</returns>
public bool IsDownloading(BeatmapSetInfo beatmap) => downloadsMap.ContainsKey(beatmap);
/// <summary> /// <summary>
/// Delete a beatmap from the manager. /// Delete a beatmap from the manager.
/// Is a no-op for already deleted beatmaps. /// Is a no-op for already deleted beatmaps.

View File

@ -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<float> DownloadProgressed;
public DownloadBeatmapSetRequest(BeatmapSetInfo beatmapSet)
{
this.beatmapSet = beatmapSet;
Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total);
}
protected override string Target => $@"beatmapsets/{beatmapSet.OnlineBeatmapSetID}/download";
}
}

View File

@ -106,9 +106,15 @@ namespace osu.Game
connection.CreateTable<StoreVersion>(); connection.CreateTable<StoreVersion>();
dependencies.Cache(API = new APIAccess
{
Username = LocalConfig.Get<string>(OsuSetting.Username),
Token = LocalConfig.Get<string>(OsuSetting.Token)
});
dependencies.Cache(RulesetStore = new RulesetStore(connection)); dependencies.Cache(RulesetStore = new RulesetStore(connection));
dependencies.Cache(FileStore = new FileStore(connection, Host.Storage)); 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(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager, RulesetStore));
dependencies.Cache(KeyBindingStore = new KeyBindingStore(connection, RulesetStore)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(connection, RulesetStore));
dependencies.Cache(new OsuColour()); dependencies.Cache(new OsuColour());
@ -144,12 +150,6 @@ namespace osu.Game
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap); Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
BeatmapManager.DefaultBeatmap = defaultBeatmap; BeatmapManager.DefaultBeatmap = defaultBeatmap;
dependencies.Cache(API = new APIAccess
{
Username = LocalConfig.Get<string>(OsuSetting.Username),
Token = LocalConfig.Get<string>(OsuSetting.Token)
});
Beatmap.ValueChanged += b => Beatmap.ValueChanged += b =>
{ {
// compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo) // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)

View File

@ -115,23 +115,8 @@ namespace osu.Game.Overlays.Direct
base.OnHoverLost(state); base.OnHoverLost(state);
} }
// this should eventually be moved to a more central place, like BeatmapManager.
private DownloadBeatmapSetRequest downloadRequest;
protected void StartDownload() 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) if (!api.LocalUser.Value.IsSupporter)
{ {
notifications.Post(new SimpleNotification notifications.Post(new SimpleNotification
@ -142,25 +127,28 @@ namespace osu.Game.Overlays.Direct
return; 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.FadeIn(400, Easing.OutQuint);
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint); progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
progressBar.Current.Value = 0; progressBar.Current.Value = 0;
ProgressNotification downloadNotification = new ProgressNotification
{
Text = $"Downloading {SetInfo.Metadata.Artist} - {SetInfo.Metadata.Title}",
};
downloadRequest = new DownloadBeatmapSetRequest(SetInfo);
downloadRequest.Failure += e => downloadRequest.Failure += e =>
{ {
progressBar.Current.Value = 0; progressBar.Current.Value = 0;
progressBar.FadeOut(500); progressBar.FadeOut(500);
downloadNotification.State = ProgressNotificationState.Completed;
Logger.Error(e, "Failed to get beatmap download information"); Logger.Error(e, "Failed to get beatmap download information");
downloadRequest = null;
}; };
downloadRequest.Progress += (current, total) => downloadRequest.Progress += (current, total) =>
@ -169,45 +157,13 @@ namespace osu.Game.Overlays.Direct
progressBar.Current.Value = progress; progressBar.Current.Value = progress;
downloadNotification.State = ProgressNotificationState.Active;
downloadNotification.Progress = progress;
}; };
downloadRequest.Success += data => downloadRequest.Success += data =>
{ {
progressBar.Current.Value = 1; progressBar.Current.Value = 1;
progressBar.FadeOut(500); 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() protected override void LoadComplete()

View File

@ -98,6 +98,7 @@
<Compile Include="Input\Bindings\GlobalKeyBindingInputManager.cs" /> <Compile Include="Input\Bindings\GlobalKeyBindingInputManager.cs" />
<Compile Include="IO\FileStore.cs" /> <Compile Include="IO\FileStore.cs" />
<Compile Include="IO\FileInfo.cs" /> <Compile Include="IO\FileInfo.cs" />
<Compile Include="Online\API\Requests\DownloadBeatmapSetRequest.cs" />
<Compile Include="Online\API\Requests\GetUsersRequest.cs" /> <Compile Include="Online\API\Requests\GetUsersRequest.cs" />
<Compile Include="Online\API\Requests\PostMessageRequest.cs" /> <Compile Include="Online\API\Requests\PostMessageRequest.cs" />
<Compile Include="Online\Chat\ErrorMessage.cs" /> <Compile Include="Online\Chat\ErrorMessage.cs" />