-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using UnityEngine; | ||
|
||
namespace Elympics | ||
{ | ||
/// <summary> | ||
/// Create leaderboard client with desired parameters and use its fetch methods with custom callbacks | ||
/// </summary> | ||
public class LeaderboardClient | ||
{ | ||
private const string LeaderboardsUrl = "https://api.elympics.cc/v2/leaderboardservice/leaderboard"; | ||
private const string LeaderboardsUserCenteredUrl = "https://api.elympics.cc/v2/leaderboardservice/leaderboard/user-centred"; | ||
|
||
private readonly Dictionary<string, string> _queryValues; | ||
|
||
private bool _isBusy; | ||
private int _currentPage = 1; | ||
|
||
/// <param name="pageSize">Must be in range 1 - 100 (inclusive)</param> | ||
/// <param name="queueName">No filtering by queue if null provided</param> | ||
public LeaderboardClient(int pageSize, LeaderboardTimeScope timeScope, string queueName = null, LeaderboardGameVersion gameVersion = LeaderboardGameVersion.All) | ||
{ | ||
if (pageSize < 1 || pageSize > 100) | ||
throw new ArgumentOutOfRangeException(nameof(pageSize), "Must be in range 1 - 100 (inclusive)"); | ||
|
||
if (timeScope == null) | ||
throw new ArgumentNullException(nameof(timeScope)); | ||
|
||
if (!Enum.IsDefined(typeof(LeaderboardGameVersion), gameVersion)) | ||
throw new ArgumentOutOfRangeException(nameof(gameVersion)); | ||
|
||
var gameConfig = ElympicsConfig.Load().GetCurrentGameConfig(); | ||
if (gameConfig == null) | ||
throw new ElympicsException("Provide ElympicsGameConfig before proceeding"); | ||
|
||
_queryValues = new Dictionary<string, string> | ||
{ | ||
{ "PageNumber", _currentPage.ToString() }, | ||
{ "PageSize", pageSize.ToString() }, | ||
{ "GameId", gameConfig.GameId }, | ||
{ "GameVersion", gameVersion == LeaderboardGameVersion.All ? null : gameConfig.GameVersion }, | ||
{ "QueueName", queueName }, | ||
{ "TimeScope", timeScope.LeaderboardTimeScopeType.ToString() }, | ||
}; | ||
|
||
if (timeScope.LeaderboardTimeScopeType == LeaderboardTimeScopeType.Custom) | ||
{ | ||
_queryValues.Add("DateFrom", timeScope.DateFrom.ToString("o")); | ||
_queryValues.Add("DateTo", timeScope.DateTo.ToString("o")); | ||
} | ||
} | ||
|
||
|
||
public void FetchFirstPage(Action<LeaderboardFetchResult> onSuccess, Action<LeaderboardFetchError> onFailure = null) => SendLeaderboardRequest(LeaderboardsUrl, 1, onSuccess, onFailure); | ||
public void FetchPageWithUser(Action<LeaderboardFetchResult> onSuccess, Action<LeaderboardFetchError> onFailure = null) => SendLeaderboardRequest(LeaderboardsUserCenteredUrl, _currentPage, onSuccess, onFailure); | ||
public void FetchNextPage(Action<LeaderboardFetchResult> onSuccess, Action<LeaderboardFetchError> onFailure = null) => SendLeaderboardRequest(LeaderboardsUrl, _currentPage + 1, onSuccess, onFailure); | ||
public void FetchPreviousPage(Action<LeaderboardFetchResult> onSuccess, Action<LeaderboardFetchError> onFailure = null) => SendLeaderboardRequest(LeaderboardsUrl, _currentPage - 1, onSuccess, onFailure); | ||
public void FetchRefreshedCurrentPage(Action<LeaderboardFetchResult> onSuccess, Action<LeaderboardFetchError> onFailure = null) => SendLeaderboardRequest(LeaderboardsUrl, _currentPage, onSuccess, onFailure); | ||
|
||
private void SendLeaderboardRequest(string url, int pageNumber, Action<LeaderboardFetchResult> onSuccess, Action<LeaderboardFetchError> onFailure) | ||
{ | ||
onFailure = onFailure ?? DefaultFailure; | ||
|
||
if (_isBusy) | ||
onFailure(LeaderboardFetchError.RequestAlreadyInProgress); | ||
else if (!ElympicsLobbyClient.Instance.IsAuthenticated) | ||
onFailure(LeaderboardFetchError.NotAuthenticated); | ||
else if (pageNumber < 1) | ||
onFailure(LeaderboardFetchError.PageLessThanOne); | ||
else | ||
{ | ||
_isBusy = true; | ||
_queryValues["PageNumber"] = pageNumber.ToString(); | ||
var authorization = ElympicsLobbyClient.Instance.AuthData.BearerAuthorization; | ||
ElympicsWebClient.SendGetRequest(url, _queryValues, authorization, HandleCallback(onSuccess, onFailure)); | ||
} | ||
} | ||
|
||
|
||
private Action<Result<LeaderboardResponse, Exception>> HandleCallback(Action<LeaderboardFetchResult> onSuccess, Action<LeaderboardFetchError> onFailure) | ||
{ | ||
return result => | ||
{ | ||
_isBusy = false; | ||
if (result.IsSuccess) | ||
{ | ||
if (result.Value?.data?.Any() is true) | ||
{ | ||
_currentPage = result.Value.pageNumber; | ||
onSuccess(new LeaderboardFetchResult(result.Value)); | ||
} | ||
else if (result.Value?.pageNumber == 1) | ||
onFailure(LeaderboardFetchError.NoRecords); | ||
else | ||
onFailure(LeaderboardFetchError.PageGreaterThanMax); | ||
} | ||
else | ||
{ | ||
var errorMessage = result.Error.ToString(); | ||
if (errorMessage.Contains("There is no score of this user in the leaderboard.")) | ||
onFailure(LeaderboardFetchError.NoScoresForUser); | ||
else if (errorMessage.Contains("401")) | ||
onFailure(LeaderboardFetchError.NotAuthenticated); | ||
else | ||
{ | ||
onFailure(LeaderboardFetchError.UnknownError); | ||
Debug.LogError(errorMessage); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
private static void DefaultFailure(LeaderboardFetchError error) => Debug.LogError(error); | ||
} | ||
|
||
public enum LeaderboardGameVersion | ||
{ | ||
All, | ||
Current, | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System; | ||
|
||
namespace Elympics | ||
{ | ||
public class LeaderboardEntry | ||
{ | ||
/// <summary> | ||
/// Raw user ID. | ||
/// It is recommended to pair it with nicknames using your own external backend. | ||
/// </summary> | ||
public string UserId { get; } | ||
public int Position { get; } | ||
public float Score { get; } | ||
public DateTimeOffset ScoredAt { get; } | ||
|
||
internal LeaderboardEntry(LeaderboardResponseEntry entry) | ||
{ | ||
UserId = entry.userId; | ||
Position = entry.position; | ||
Score = entry.points; | ||
ScoredAt = DateTimeOffset.Parse(entry.endedAt); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace Elympics | ||
{ | ||
public enum LeaderboardFetchError | ||
{ | ||
UnknownError = 0, | ||
|
||
NoRecords = 101, | ||
PageLessThanOne = 102, | ||
PageGreaterThanMax = 103, | ||
NoScoresForUser = 104, | ||
|
||
RequestAlreadyInProgress = 201, | ||
|
||
NotAuthenticated = 301, | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Elympics | ||
{ | ||
public class LeaderboardFetchResult | ||
{ | ||
public List<LeaderboardEntry> Entries { get; } | ||
public int TotalRecords { get; } | ||
public int PageNumber { get; } | ||
|
||
internal LeaderboardFetchResult(LeaderboardResponse response) | ||
{ | ||
if (response == null) | ||
return; | ||
|
||
Entries = response.data?.Select(x => new LeaderboardEntry(x)).ToList(); | ||
TotalRecords = response.totalRecords; | ||
PageNumber = response.pageNumber; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System; | ||
|
||
namespace Elympics | ||
{ | ||
public class LeaderboardTimeScope | ||
{ | ||
public LeaderboardTimeScopeType LeaderboardTimeScopeType { get; } | ||
public DateTimeOffset DateFrom { get; } | ||
public DateTimeOffset DateTo { get; } | ||
|
||
private const int MaxDaysSpan = 31; | ||
|
||
public LeaderboardTimeScope(LeaderboardTimeScopeType leaderboardTimeScopeType) | ||
{ | ||
if (!Enum.IsDefined(typeof(LeaderboardTimeScopeType), leaderboardTimeScopeType)) | ||
throw new ArgumentOutOfRangeException(nameof(leaderboardTimeScopeType)); | ||
|
||
if (leaderboardTimeScopeType == LeaderboardTimeScopeType.Custom) | ||
throw new ArgumentException("To declare custom time scope use constructor with DateTime parameters"); | ||
|
||
LeaderboardTimeScopeType = leaderboardTimeScopeType; | ||
} | ||
|
||
public LeaderboardTimeScope(DateTimeOffset dateFrom, DateTimeOffset dateTo) | ||
{ | ||
if (dateFrom >= dateTo) | ||
throw new ArgumentException($"{nameof(dateFrom)} must be before {nameof(dateTo)}"); | ||
|
||
if ((dateTo - dateFrom).TotalDays > MaxDaysSpan) | ||
throw new ArgumentException($"Maximal accepted date difference is {MaxDaysSpan} days"); | ||
|
||
LeaderboardTimeScopeType = LeaderboardTimeScopeType.Custom; | ||
DateFrom = dateFrom; | ||
DateTo = dateTo; | ||
} | ||
|
||
public LeaderboardTimeScope(DateTimeOffset dateStart, TimeSpan timeSpan) : this(dateStart, dateStart + timeSpan) | ||
{ } | ||
} | ||
|
||
public enum LeaderboardTimeScopeType | ||
{ | ||
AllTime = 0, | ||
Month = 1, | ||
Day = 2, | ||
Custom = 3, | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System; | ||
|
||
namespace Elympics | ||
{ | ||
internal class LeaderboardResponse : PaginatedResponseModel<LeaderboardResponseEntry> { } | ||
|
||
[Serializable] | ||
internal class LeaderboardResponseEntry | ||
{ | ||
public string userId; | ||
public string matchId; | ||
public int position; | ||
public float points; | ||
public string endedAt; | ||
}; | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Elympics | ||
{ | ||
[Serializable] | ||
internal class PaginatedResponseModel<T> | ||
{ | ||
public List<T> data; | ||
public int pageNumber; | ||
public int pageSize; | ||
public int totalPages; | ||
public int totalRecords; | ||
|
||
public string firstPage; | ||
public string lastPage; | ||
public string nextPage; | ||
public string previousPage; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.