Skip to content

DB reader update, API throttling #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 5 additions & 23 deletions osuElements/Api/Repositories/ApiBeatmapRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,20 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osuElements.Api.Throttling;
using osuElements.Helpers;
using static osuElements.Helpers.Constants;

namespace osuElements.Api.Repositories
{
public class ApiBeatmapRepository : ApiRepositoryBase, IApiBeatmapRepository
{
Lazy<IApiScoreRepository> _apiScoreRepository;

public ApiBeatmapRepository()
{
_apiScoreRepository = new Lazy<IApiScoreRepository>(() => new ApiScoreRepository(), true);
}
public ApiBeatmapRepository() : base() { }

public ApiBeatmapRepository(string apiKey, bool throwExceptions, IThrottler throttler) : base(apiKey, throwExceptions, throttler) { }


public ApiBeatmapRepository(IApiScoreRepository apiScoreRepository)
{
_apiScoreRepository = new Lazy<IApiScoreRepository>(() => apiScoreRepository, true);
}

public async Task<List<ApiBeatmap>> GetSince(DateTime time, GameMode? mode = null, int limit = MaxApiBeatmapResults) {
return await GetMaps(
Expand Down Expand Up @@ -53,20 +49,6 @@ public async Task<ApiBeatmap> Get(string mapHash, GameMode? mode = null) {
return (await GetMaps($"get_beatmaps?h={mapHash}", mode))?.FirstOrDefault();
}

// Left for backward compatibility
public async Task<List<ApiScore>> GetScores(int mapId, int? userid = null, string username = null,
GameMode mode = 0, Mods? mods = null, int limit = MaxApiBeatmapResults) {

if (userid.HasValue) {
return await CallNestedRepository(_apiScoreRepository.Value, async (repo) => await
repo.GetMapScores(mapId, userid.Value, mode, mods, limit));
}
else {
return await CallNestedRepository(_apiScoreRepository.Value, async (repo) => await
repo.GetMapScores(mapId, username, mode, mods, limit));
}

}

private async Task<List<ApiBeatmap>> GetMaps(string query, GameMode? mode) {
var modestring = mode.HasValue && mode.Value != GameMode.Standard ? $"&m={(int)mode.Value}&a=1" : "";
Expand Down
8 changes: 8 additions & 0 deletions osuElements/Api/Repositories/ApiMultiplayerRepository.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
using System.Linq;
using System.Threading.Tasks;
using osuElements.Api.Throttling;

namespace osuElements.Api.Repositories
{
public class ApiMultiplayerRepository : ApiRepositoryBase, IApiMultiplayerRepository
{

public ApiMultiplayerRepository() : base() { }

public ApiMultiplayerRepository(string apiKey, bool throwExceptions, IThrottler throttler) : base(apiKey, throwExceptions, throttler) { }



public async Task<ApiMatchResult> Get(int matchId) {
var result = (await GetList<ApiMatchResult>($"get_match?id={matchId}"))?.FirstOrDefault();
if (result == null) return null;
Expand Down
8 changes: 8 additions & 0 deletions osuElements/Api/Repositories/ApiReplayRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using osuElements.Api.Throttling;

namespace osuElements.Api.Repositories
{
public class ApiReplayRepository: ApiRepositoryBase, IApiReplayRepository
{

public ApiReplayRepository() : base() { }

public ApiReplayRepository(string apiKey, bool throwExceptions, IThrottler throttler) : base(apiKey, throwExceptions, throttler) { }



public async Task<ApiReplay> Get(int mapId, int userId, GameMode mode) {
return await GetData<ApiReplay>($"get_replay?b={mapId}&u={userId}&m={(int) mode}");
}
Expand Down
49 changes: 22 additions & 27 deletions osuElements/Api/Repositories/ApiRepositoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,38 @@
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using osuElements.Api.Throttling;

namespace osuElements.Api.Repositories
{
public abstract class ApiRepositoryBase : IApiRepository
{
private readonly IThrottler _throttler;

#region Properties
public static string Url { get; } = "https://osu.ppy.sh/api/";
public static string Key { protected get; set; }

public static bool ThrowExceptionsDefault { get; set; } = false;
public string Key { get; set; }

public static bool ThrowExceptions { get; set; } = ThrowExceptionsDefault;
public bool ThrowExceptions { get; set; }

public bool IsError { get; protected set; }

public ApiError ApiError { get; protected set; }
#endregion

public ApiRepositoryBase(string apiKey, bool throwExceptions, IThrottler throttler)
{
Key = apiKey;
ThrowExceptions = throwExceptions;
_throttler = throttler;
}

public ApiRepositoryBase()
{
Key = osuElements.ApiKey;
ThrowExceptions = osuElements.ApiRepositoryThrowExceptions;
_throttler = osuElements.ApiRepositoryThrottler;
}


#region GetList
Expand All @@ -50,7 +64,10 @@ protected async Task<T> GetData<T>(string query) {
string jsonResult = null;

using (var client = new HttpClient()) {


if (_throttler != null)
await _throttler.WaitAsync();

var response = await client.GetAsync(url);

jsonResult = await response.Content.ReadAsStringAsync();
Expand All @@ -77,24 +94,6 @@ protected async Task<T> GetData<T>(string query) {

#endregion

#region CallNestedRepository

protected TResult CallNestedRepository<TRepository, TResult>(TRepository repo, Func<TRepository, TResult> callFunc)
where TRepository : IApiRepository
{
try {
return callFunc(repo);
}
catch {
throw;
}
finally {
SetError(repo.IsError, repo.ApiError);
}
}

#endregion



#region SetError
Expand All @@ -120,10 +119,6 @@ protected virtual void SetError(string jsonResult) {
}
}

#endregion

#region SetError

protected virtual void SetError(bool isError, ApiError apiError) {
IsError = isError;
ApiError = apiError;
Expand Down
12 changes: 10 additions & 2 deletions osuElements/Api/Repositories/ApiScoreRepository.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
using osuElements.Helpers;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static osuElements.Helpers.Constants;
using osuElements.Api.Throttling;
using osuElements.Helpers;

namespace osuElements.Api.Repositories
{
public class ApiScoreRepository : ApiRepositoryBase, IApiScoreRepository
{

public ApiScoreRepository() : base() { }

public ApiScoreRepository(string apiKey, bool throwExceptions, IThrottler throttler) : base(apiKey, throwExceptions, throttler) { }



public async Task<List<ApiScore>> GetMapScores(int mapId, int userid, GameMode mode = GameMode.Standard, Mods? mods = null, int limit = MaxApiScoreResults)
{
var modstring = mods.HasValue ? $"&mods={(int)mods.Value}" : "";
Expand Down
40 changes: 5 additions & 35 deletions osuElements/Api/Repositories/ApiUserRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,20 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osuElements.Api.Throttling;
using osuElements.Helpers;
using static osuElements.GameMode;
using static osuElements.Helpers.Constants;

namespace osuElements.Api.Repositories
{
public class ApiUserRepository : ApiRepositoryBase, IApiUserRepository
{
Lazy<IApiScoreRepository> _apiScoreRepository;

public ApiUserRepository()
{
_apiScoreRepository = new Lazy<IApiScoreRepository>(() => new ApiScoreRepository(), true);
}
public ApiUserRepository() : base() { }

public ApiUserRepository(string apiKey, bool throwExceptions, IThrottler throttler) : base(apiKey, throwExceptions, throttler) { }


public ApiUserRepository(IApiScoreRepository apiScoreRepository)
{
_apiScoreRepository = new Lazy<IApiScoreRepository>(() => apiScoreRepository, true);
}

public async Task<ApiUser> Get(string name, GameMode mode = 0, int eventDays = MaxApiEventDays)
{
Expand All @@ -47,30 +42,5 @@ public async Task<ApiUser> Get(int id, GameMode mode = 0, int eventDays = MaxApi
return result;
}

// Methods below left for backward compatibility

public async Task<List<ApiScore>> GetBest(int id, GameMode mode = Standard, int limit = MaxApiScoreResults)
{
return await CallNestedRepository(_apiScoreRepository.Value, async (repo) => await
repo.GetUserBest(id, mode, limit));
}

public async Task<List<ApiScore>> GetBest(string name, GameMode mode = Standard, int limit = MaxApiScoreResults)
{
return await CallNestedRepository(_apiScoreRepository.Value, async (repo) => await
repo.GetUserBest(name, mode, limit));
}

public async Task<List<ApiScore>> GetRecent(int id, GameMode mode = Standard, int limit = MaxApiScoreResults)
{
return await CallNestedRepository(_apiScoreRepository.Value, async (repo) => await
repo.GetUserBest(id, mode, limit));
}

public async Task<List<ApiScore>> GetRecent(string name, GameMode mode = Standard, int limit = MaxApiScoreResults)
{
return await CallNestedRepository(_apiScoreRepository.Value, async (repo) => await
repo.GetUserBest(name, mode, limit));
}
}
}
85 changes: 42 additions & 43 deletions osuElements/Api/Repositories/IApiRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,37 +38,6 @@ public interface IApiUserRepository : IApiRepository
/// <param name="mode">the gamemode for the data</param>
/// <param name="eventDays">max amount of days for the event data, between 1 and 31</param>
Task<ApiUser> Get(int id, GameMode mode = Standard, int eventDays = MaxApiEventDays);

/// <summary>
/// Returns the top scores for the specified user.
/// </summary>
/// <param name="name">username, cannot be ID</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetBest(string name, GameMode mode = Standard, int limit = MaxApiScoreResults);
/// <summary>
/// Returns the top scores for the specified user.
/// </summary>
/// <param name="id">user ID, cannot be name</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetBest(int id, GameMode mode = Standard, int limit = MaxApiScoreResults);

/// <summary>
/// Returns most recent scores for the specified user.
/// </summary>
/// <param name="name">username, cannot be ID</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetRecent(string name, GameMode mode = Standard, int limit = MaxApiScoreResults);

/// <summary>
/// Returns most recent scores for the specified user.
/// </summary>
/// <param name="id">user ID, cannot be name</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetRecent(int id, GameMode mode = Standard, int limit = MaxApiScoreResults);
}

public interface IApiBeatmapRepository : IApiRepository
Expand Down Expand Up @@ -113,16 +82,6 @@ public interface IApiBeatmapRepository : IApiRepository
/// <param name="mapHash">the beatmap hash</param>
/// <param name="mode">optional, only gamemode to return results from</param>
Task<ApiBeatmap> Get(string mapHash, GameMode? mode = null);
/// <summary>
/// Returns the top scores for the specified beatmap.
/// </summary>
/// <param name="mapId">beatmap ID</param>
/// <param name="userid">optional, specify a user's ID to get a score for</param>
/// <param name="username">optional, specify a user's username to get a score for</param>
/// <param name="mode">optional, specify a gamemode to get scores for</param>
/// <param name="mods">optional, specify mods to get scores for</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetScores(int mapId, int? userid = null, string username = null, GameMode mode = Standard, Mods? mods = null, int limit = MaxApiScoreResults);
}

public interface IApiReplayRepository : IApiRepository
Expand Down Expand Up @@ -154,16 +113,56 @@ public interface IApiMultiplayerRepository : IApiRepository

public interface IApiScoreRepository : IApiRepository
{
/// <summary>
/// Returns the top scores for the specified user.
/// </summary>
/// <param name="id">user ID, cannot be name</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetUserBest(int userId, GameMode mode = Standard, int limit = MaxApiScoreResults);

/// <summary>
/// Returns the top scores for the specified user.
/// </summary>
/// <param name="userName">username, cannot be ID</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetUserBest(string userName, GameMode mode = Standard, int limit = MaxApiScoreResults);

/// <summary>
/// Returns most recent scores for the specified user.
/// </summary>
/// <param name="userId">user ID, cannot be name</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetUserRecent(int userId, GameMode mode = Standard, int limit = MaxApiScoreResults);

/// <summary>
/// Returns most recent scores for the specified user.
/// </summary>
/// <param name="userName">username, cannot be ID</param>
/// <param name="mode">the gamemode for the data</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetUserRecent(string userName, GameMode mode = Standard, int limit = MaxApiScoreResults);

Task<List<ApiScore>> GetMapScores(int mapId, string username = null, GameMode mode = Standard, Mods? mods = null, int limit = MaxApiScoreResults);
/// <summary>
/// Returns the top scores for the specified beatmap.
/// </summary>
/// <param name="mapId">beatmap ID</param>
/// <param name="userName">optional, specify a user's username to get a score for</param>
/// <param name="mode">optional, specify a gamemode to get scores for</param>
/// <param name="mods">optional, specify mods to get scores for</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetMapScores(int mapId, string userName = null, GameMode mode = Standard, Mods? mods = null, int limit = MaxApiScoreResults);

Task<List<ApiScore>> GetMapScores(int mapId, int userid, GameMode mode = Standard, Mods? mods = null, int limit = MaxApiScoreResults);
/// <summary>
/// Returns the top scores for the specified beatmap.
/// </summary>
/// <param name="mapId">beatmap ID</param>
/// <param name="userId">optional, specify a user's ID to get a score for</param>
/// <param name="mode">optional, specify a gamemode to get scores for</param>
/// <param name="mods">optional, specify mods to get scores for</param>
/// <param name="limit">max amount of results, between 1 and 100</param>
Task<List<ApiScore>> GetMapScores(int mapId, int userId, GameMode mode = Standard, Mods? mods = null, int limit = MaxApiScoreResults);
}
}
14 changes: 14 additions & 0 deletions osuElements/Api/Throttling/IThrottler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace osuElements.Api.Throttling
{
public interface IThrottler: IDisposable
{
Task WaitAsync();
}
}
Loading