Skip to content

Commit

Permalink
adding rate limiter for WCL
Browse files Browse the repository at this point in the history
  • Loading branch information
gngrninja committed Dec 9, 2018
1 parent 37b917f commit 7f2300c
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 38 deletions.
59 changes: 59 additions & 0 deletions Modules/Wow/ApiRequestorThrottle.cs
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace NinjaBotCore.Modules.Wow
{
/// <summary>
/// Used to send throttled HTTP requests to https://api.rocketleaguestats.com.
/// Automatically detects your rate limit configuration from the headers.
/// </summary>
internal class ApiRequesterThrottle : WclApiRequestor
{
private readonly Semaphore _queue;

private int _rateLimitRemaining;

private DateTime _rateLimitResetRemaining;

public ApiRequesterThrottle(string apiKey) : base(apiKey)
{
_queue = new Semaphore(1, 1);
_rateLimitRemaining = 1;
_rateLimitResetRemaining = DateTime.UtcNow.AddSeconds(1);
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
{
try
{
_queue.WaitOne();

if (_rateLimitRemaining == 0)
{
var startTime = DateTime.UtcNow;
//var difference = _rateLimitResetRemaining - startTime;
//System.Console.WriteLine($"dif: {difference}");

await Task.Delay(1000);

_rateLimitRemaining = 1;
_rateLimitResetRemaining.AddSeconds(1);
}

var response = await base.SendAsync(request);
_rateLimitRemaining -= 1;
_rateLimitResetRemaining = _rateLimitResetRemaining.AddSeconds(-1);
//System.Console.WriteLine(_rateLimitRemaining);
return response;
}
finally
{
_queue.Release();
}
}
}
}
61 changes: 23 additions & 38 deletions Modules/Wow/WarcraftLogs.cs
Expand Up @@ -24,16 +24,19 @@ public class WarcraftLogs
private static List<CharClasses> _charClasses;
private readonly IConfigurationRoot _config;
private DiscordSocketClient _client;
private readonly WclApiRequestor _api;

public WarcraftLogs(IConfigurationRoot config, DiscordSocketClient client)
public WarcraftLogs(IConfigurationRoot config, DiscordSocketClient client, bool throttle = true)
{
_client = client;
_config = config;

try
{
Zones = this.GetZones();
CharClasses = this.GetCharClasses();
this.StartTimer();
_api = throttle ? new ApiRequesterThrottle(_config["WarcraftLogsApi"]) : new WclApiRequestor(_config["WarcraftLogsApi"]);
CharClasses = this.GetCharClasses().Result;
Zones = this.GetZones().Result;
//this.StartTimer();
}
catch (Exception ex)
{
Expand Down Expand Up @@ -82,7 +85,7 @@ public async Task<string> LogsApiRequestAsync(string url, bool isList = false)
string response = string.Empty;
string wowLogsKey = string.Empty;
string baseUrl = "https://www.warcraftlogs.com:443/v1";

if (isList)
{
wowLogsKey = $"api_key={_config["WarcraftLogsApi"]}";
Expand Down Expand Up @@ -139,14 +142,9 @@ public string LogsApiRequest(string url, bool isList = false)
return response;
}

public List<CharClasses> GetCharClasses()
public async Task<List<CharClasses>> GetCharClasses()
{
List<CharClasses> charClasses;
string url = "/classes?";

charClasses = JsonConvert.DeserializeObject<List<CharClasses>>(LogsApiRequest(url));

return charClasses;
return await _api.Get<List<CharClasses>>($"classes?api_key={_config["WarcraftLogsApi"]}");
}

public async Task<List<Reports>> GetReportsFromGuild(string guildName, string realm, string region, bool isList = false)
Expand All @@ -167,12 +165,10 @@ public async Task<List<Reports>> GetReportsFromGuild(string guildName, string re
}
}
System.Console.WriteLine($"SLUG: {realmSlug}");
url = $"/reports/guild/{guildName.Replace(" ", "%20")}/{realmSlug}/{region}?";
List<Reports> logs;
url = $"reports/guild/{guildName.Replace(" ", "%20")}/{realmSlug}/{region}?api_key={_config["WarcraftLogsApi"]}";

logs = JsonConvert.DeserializeObject<List<Reports>>(await LogsApiRequestAsync(url, isList));
return await _api.Get<List<Reports>>(url);

return logs;
}

public async Task<List<Reports>> GetReportsFromGuild(string guildName, string realm, string locale, string region, bool isList = false)
Expand All @@ -197,34 +193,25 @@ public async Task<List<Reports>> GetReportsFromGuild(string guildName, string re
break;
}
}
url = $"/reports/guild/{guildName.Replace(" ", "%20")}/{realmSlug}/{region}?";
List<Reports> logs;
url = $"reports/guild/{guildName.Replace(" ", "%20")}/{realmSlug}/{region}?api_key={_config["WarcraftLogsApi"]}";


logs = JsonConvert.DeserializeObject<List<Reports>>(await LogsApiRequestAsync(url, isList));

return logs;
return await _api.Get<List<Reports>>(url);
}

public async Task<List<Reports>> GetReportsFromGuild(string guildName, string realm, string locale, string region, string realmSlug , bool isList = false)
{
string url = string.Empty;
url = $"/reports/guild/{guildName.Replace(" ", "%20")}/{realmSlug}/{region}?";
List<Reports> logs;

logs = JsonConvert.DeserializeObject<List<Reports>>(await LogsApiRequestAsync(url, isList));
url = $"reports/guild/{guildName.Replace(" ", "%20")}/{realmSlug}/{region}?api_key={_config["WarcraftLogsApi"]}";

return logs;
return await _api.Get<List<Reports>>(url);
}

public async Task<List<Reports>> GetReportsFromUser(string userName)
{
string url = string.Empty;
url = $"/reports/user/{userName.Replace(" ", "%20")}?";
List<Reports> logs;

logs = JsonConvert.DeserializeObject<List<Reports>>(await LogsApiRequestAsync(url));

return logs;
url = $"/reports/user/{userName.Replace(" ", "%20")}?api_key={_config["WarcraftLogsApi"]}";
return await _api.Get<List<Reports>>(url);
}

public List<CharParses> GetParsesFromCharacterName(string charName, string realm, string region = "us")
Expand Down Expand Up @@ -286,15 +273,13 @@ public List<LogCharRankings> GetRankingFromCharName(string charName, string real
return charRankings;
}

public List<Zones> GetZones()
public async Task<List<Zones>> GetZones()
{
string url = string.Empty;
url = "/zones?";
List<Zones> zones;

zones = JsonConvert.DeserializeObject<List<Zones>>(LogsApiRequest(url));
url = $"zones?api_key={_config["WarcraftLogsApi"]}";


return zones;
return await _api.Get<List<Zones>>(url);
}

public Fights GetFights(string code)
Expand Down
79 changes: 79 additions & 0 deletions Modules/Wow/WclApiRequestor.cs
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using Newtonsoft.Json;
using NinjaBotCore.Models.Wow;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using NinjaBotCore.Database;
using Discord;
using Discord.Net;
using Discord.WebSocket;
using Microsoft.Extensions.Configuration;

namespace NinjaBotCore.Modules.Wow
{
public class WclApiRequestor : IDisposable
{
private readonly HttpClient _client;

public WclApiRequestor(string apiKey)
{
_client = new HttpClient
{
BaseAddress = new Uri("https://www.warcraftlogs.com:443/v1/"),
};
_client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}

public async Task<T> Get<T>(string relativeUrl)
{

System.Console.WriteLine($"{relativeUrl}");
using (var request = new HttpRequestMessage(HttpMethod.Get, relativeUrl))
using (var response = await SendAsync(request))
{
var result = await response.Content.ReadAsStringAsync();

return JsonConvert.DeserializeObject<T>(result);
}
}

protected virtual async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
{
var response = await _client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return response;
}

try
{
var errorMessage = await response.Content.ReadAsStringAsync();

if (string.IsNullOrEmpty(errorMessage))
{
throw new Exception("No message!");
} else {
throw new Exception($"{errorMessage}");
}

}
catch (JsonException e)
{
throw new Exception($"{e.Message}");
}
}

public void Dispose()
{
_client?.Dispose();
}
}
}
1 change: 1 addition & 0 deletions NinjaBotCore.csproj
Expand Up @@ -20,6 +20,7 @@
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="RLSApi" Version="1.4.0" />
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3.linux" Version="1.1.11" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" />
Expand Down

0 comments on commit 7f2300c

Please sign in to comment.