diff --git a/src/RLSApi.Example/Program.cs b/src/RLSApi.Example/Program.cs index 12f5da2..19a1fb7 100644 --- a/src/RLSApi.Example/Program.cs +++ b/src/RLSApi.Example/Program.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using RLSApi.Data; using RLSApi.Net.Requests; @@ -16,20 +17,30 @@ private static async Task Run() var apiKey = Environment.GetEnvironmentVariable("RLS_API_KEY"); // Initialize RLSClient. - var client = new RLSClient(apiKey); + var client = new RLSClient(apiKey, httpExceptionHandler: async res => + { + Console.WriteLine(res.ToString()); + }); // Retrieve a single player. - var player = await client.GetPlayerAsync(RlsPlatform.Steam, "76561198033338223"); - var playerSeasonSix = player.RankedSeasons.FirstOrDefault(x => x.Key == RlsSeason.Six); - if (playerSeasonSix.Value != null) + var player = await client.GetPlayerAsync(RlsPlatform.Steam, "7656198033338223"); + if (player != null) { - Console.WriteLine($"# Player: {player.DisplayName}"); - - foreach (var playerRank in playerSeasonSix.Value) + var playerSeasonSix = player.RankedSeasons.FirstOrDefault(x => x.Key == RlsSeason.Six); + if (playerSeasonSix.Value != null) { - Console.WriteLine($"{playerRank.Key}: {playerRank.Value.RankPoints} rating"); + Console.WriteLine($"# Player: {player.DisplayName}"); + + foreach (var playerRank in playerSeasonSix.Value) + { + Console.WriteLine($"{playerRank.Key}: {playerRank.Value.RankPoints} rating"); + } } } + else + { + Console.WriteLine("Could not find player"); + } // Retrieve multiple players. var players = await client.GetPlayersAsync(new[] diff --git a/src/RLSApi.sln b/src/RLSApi.sln index 1bd67ae..2d40adf 100644 --- a/src/RLSApi.sln +++ b/src/RLSApi.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.15 +VisualStudioVersion = 15.0.26730.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RLSApi", "RLSApi\RLSApi.csproj", "{75321AB1-50FE-4112-902A-C2604DDB8932}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RLSApi.Example", "RLSApi.Example\RLSApi.Example.csproj", "{CE55593F-FC7B-4DE0-A384-EAD9482C6882}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RLSApi.Example", "RLSApi.Example\RLSApi.Example.csproj", "{CE55593F-FC7B-4DE0-A384-EAD9482C6882}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -25,4 +25,10 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {556BF256-7FFC-4E2E-BDD8-7864EE452270} + EndGlobalSection + GlobalSection(CodealikeProperties) = postSolution + SolutionGuid = f2712b56-43fc-4d5f-b1bc-913862bc7876 + EndGlobalSection EndGlobal diff --git a/src/RLSApi/Net/ApiRequester.cs b/src/RLSApi/Net/ApiRequester.cs index ca99632..f13c11f 100644 --- a/src/RLSApi/Net/ApiRequester.cs +++ b/src/RLSApi/Net/ApiRequester.cs @@ -14,8 +14,9 @@ namespace RLSApi.Net internal class ApiRequester : IDisposable { private readonly HttpClient _client; + private readonly Func _httpExceptionHandler; - public ApiRequester(string apiKey) + public ApiRequester(string apiKey, Func exceptionHandler = null) { _client = new HttpClient { @@ -25,71 +26,74 @@ public ApiRequester(string apiKey) { "Authorization", apiKey } } }; + + _httpExceptionHandler = exceptionHandler ?? (async response => + { + try + { + var errorMessage = await response.Content.ReadAsStringAsync(); + + if (string.IsNullOrEmpty(errorMessage)) + { + throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), there was no error message available.") + { + HttpStatusCode = (int)response.StatusCode + }; + } + + var error = JsonConvert.DeserializeObject(errorMessage); + + throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), RLS: '{error.Message}'.") + { + HttpStatusCode = (int)response.StatusCode, + RlsError = error + }; + } + catch (JsonException e) + { + throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), we were unable to parse the error message.", e) + { + HttpStatusCode = (int)response.StatusCode + }; + } + }); } public async Task Get(string relativeUrl) { using (var request = new HttpRequestMessage(HttpMethod.Get, relativeUrl)) - using (var response = await SendAsync(request)) - { - var result = await response.Content.ReadAsStringAsync(); + return await SendAndReceiveAsync(request); - return JsonConvert.DeserializeObject(result); - } } + + public async Task Post(string relativeUrl, object data) { using (var request = new HttpRequestMessage(HttpMethod.Post, relativeUrl)) { var requestData = JsonConvert.SerializeObject(data, Formatting.None); request.Content = new StringContent(requestData, Encoding.UTF8, "application/json"); + return await SendAndReceiveAsync(request); - using (var response = await SendAsync(request)) - { - var result = await response.Content.ReadAsStringAsync(); - - return JsonConvert.DeserializeObject(result); - } } } - protected virtual async Task SendAsync(HttpRequestMessage request) + private async Task SendAndReceiveAsync(HttpRequestMessage request) { - var response = await _client.SendAsync(request); + var response = await SendAsync(request); if (response.IsSuccessStatusCode) - { - return response; - } - - try - { - var errorMessage = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + await _httpExceptionHandler.Invoke(response); + return default(T); + } - if (string.IsNullOrEmpty(errorMessage)) - { - throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), there was no error message available.") - { - HttpStatusCode = (int)response.StatusCode - }; - } + protected virtual async Task SendAsync(HttpRequestMessage request) + { + return await _client.SendAsync(request); + } - var error = JsonConvert.DeserializeObject(errorMessage); - throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), RLS: '{error.Message}'.") - { - HttpStatusCode = (int)response.StatusCode, - RlsError = error - }; - } - catch (JsonException e) - { - throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), we were unable to parse the error message.", e) - { - HttpStatusCode = (int)response.StatusCode - }; - } - } public void Dispose() { diff --git a/src/RLSApi/Net/ApiRequesterThrottle.cs b/src/RLSApi/Net/ApiRequesterThrottle.cs index 084a286..55d4440 100644 --- a/src/RLSApi/Net/ApiRequesterThrottle.cs +++ b/src/RLSApi/Net/ApiRequesterThrottle.cs @@ -19,7 +19,7 @@ internal class ApiRequesterThrottle : ApiRequester private DateTime _rateLimitResetRemaining; - public ApiRequesterThrottle(string apiKey) : base(apiKey) + public ApiRequesterThrottle(string apiKey, Func exceptionHandler = null) : base(apiKey, exceptionHandler) { _queue = new Semaphore(1, 1); _rateLimitRemaining = 2; @@ -45,11 +45,11 @@ protected override async Task SendAsync(HttpRequestMessage var response = await base.SendAsync(request); - if (response.Headers.TryGetValues("x-rate-limit-remaining", out IEnumerable rateLimitRemainingValues) && - response.Headers.TryGetValues("x-rate-limit-reset-remaining", out IEnumerable rateLimitResetValues)) + if (response.Headers.TryGetValues("x-rate-limit-remaining", out var rateLimitRemainingValues) && + response.Headers.TryGetValues("x-rate-limit-reset-remaining", out var rateLimitResetValues)) { - if (int.TryParse(rateLimitRemainingValues.First(), out int rateLimitRemaining) && - int.TryParse(rateLimitResetValues.First(), out int rateLimitResetRemaining)) + if (int.TryParse(rateLimitRemainingValues.First(), out var rateLimitRemaining) && + int.TryParse(rateLimitResetValues.First(), out var rateLimitResetRemaining)) { _rateLimitRemaining = rateLimitRemaining; _rateLimitResetRemaining = DateTime.UtcNow.AddMilliseconds(rateLimitResetRemaining); diff --git a/src/RLSApi/RLSClient.cs b/src/RLSApi/RLSClient.cs index fb9226a..bcda344 100644 --- a/src/RLSApi/RLSClient.cs +++ b/src/RLSApi/RLSClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using RLSApi.Data; using RLSApi.Net; @@ -13,9 +14,9 @@ public class RLSClient : IDisposable { private readonly ApiRequester _api; - public RLSClient(string apiKey, bool throttle = true) + public RLSClient(string apiKey, bool throttle = true, Func httpExceptionHandler = null) { - _api = throttle ? new ApiRequesterThrottle(apiKey) : new ApiRequester(apiKey); + _api = throttle ? new ApiRequesterThrottle(apiKey, httpExceptionHandler) : new ApiRequester(apiKey, httpExceptionHandler); } ///