diff --git a/FortnoxAPILibrary.Tests/TestErrorScenarios.cs b/FortnoxAPILibrary.Tests/TestErrorScenarios.cs index de95b1d6..08137685 100644 --- a/FortnoxAPILibrary.Tests/TestErrorScenarios.cs +++ b/FortnoxAPILibrary.Tests/TestErrorScenarios.cs @@ -45,6 +45,7 @@ public void Test_NoRateLimiter_TooManyRequest_Error() ErrorInformation error = null; for (var i = 0; i < 200; i++) { + connector.City = TestUtils.RandomString(); connector.Find(); if (connector.HasError) { @@ -57,6 +58,7 @@ public void Test_NoRateLimiter_TooManyRequest_Error() ConnectionSettings.UseRateLimiter = true; //Assert + //Assert.IsTrue(failed > 0); Assert.IsNotNull(error); Assert.IsTrue(error.Message.Contains("Too Many Requests")); } } diff --git a/FortnoxAPILibrary/BaseClient.cs b/FortnoxAPILibrary/BaseClient.cs index 653130d9..8b6ef6c2 100644 --- a/FortnoxAPILibrary/BaseClient.cs +++ b/FortnoxAPILibrary/BaseClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -11,25 +12,18 @@ public class BaseClient { private const string AccessTokenHeader = "Access-Token"; private const string ClientSecretHeader = "Client-Secret"; - + + private const int LimitPerSecond = 3; + private static readonly Dictionary RateLimiters = new Dictionary(); + /// /// Http client used under-the-hood for all request (except file upload due to a server-side limitation) /// private HttpClient HttpClient { get; } - /// - /// Optional Fortnox Access Token, if used it will override the static version. - /// public string AccessToken { get; set; } - - /// - /// Optional Fortnox Client Secret, if used it will override the static version. - /// public string ClientSecret { get; set; } - /// - /// Timeout of requests sent to the Fortnox API in miliseconds - /// public int Timeout { get => (int) HttpClient.Timeout.TotalMilliseconds; @@ -39,17 +33,10 @@ public int Timeout /// /// Base fortnox server URI /// - public string BaseUrl - { - get => HttpClient.BaseAddress.AbsoluteUri; - set => HttpClient.BaseAddress = new Uri(value); - } + public string BaseUrl { get; set; } public bool UseRateLimiter { get; set; } - private const int LimitPerSecond = 3; - private static readonly TimeLimiter RateLimiter = TimeLimiter.GetFromMaxCountByInterval(LimitPerSecond, TimeSpan.FromSeconds(1)); - public BaseClient() { HttpClient = new HttpClient(); @@ -57,7 +44,7 @@ public BaseClient() AccessToken = ConnectionCredentials.AccessToken; ClientSecret = ConnectionCredentials.ClientSecret; BaseUrl = ConnectionSettings.FortnoxAPIServer; - Timeout = 30 * 10000; + Timeout = ConnectionSettings.Timeout; UseRateLimiter = ConnectionSettings.UseRateLimiter; } @@ -67,7 +54,7 @@ public async Task SendAsync(HttpRequestMessage request) request.Headers.Add(ClientSecretHeader, ClientSecret); if (UseRateLimiter) - await RateLimiter; //throttle every call to Fortnox + await Throttle(); return await HttpClient.SendAsync(request).ConfigureAwait(false); } @@ -79,9 +66,21 @@ public async Task SendAsync(HttpWebRequest request) request.Timeout = Timeout; if (UseRateLimiter) - await RateLimiter; //throttle every call to Fortnox + await Throttle(); return (HttpWebResponse) await request.GetResponseAsync().ConfigureAwait(false); } + + private async Task Throttle() + { + if (string.IsNullOrEmpty(AccessToken)) + return; + + //Add ratelimiter for access token if does not exist + if (!RateLimiters.ContainsKey(AccessToken)) + RateLimiters.Add(AccessToken, TimeLimiter.GetFromMaxCountByInterval(LimitPerSecond, TimeSpan.FromSeconds(1))); + + await RateLimiters[AccessToken]; + } } } diff --git a/FortnoxAPILibrary/ConnectionSettings.cs b/FortnoxAPILibrary/ConnectionSettings.cs index fd8f7591..b084c13f 100644 --- a/FortnoxAPILibrary/ConnectionSettings.cs +++ b/FortnoxAPILibrary/ConnectionSettings.cs @@ -16,5 +16,10 @@ public static class ConnectionSettings /// API Server URL /// public static string FortnoxAPIServer { get; set; } = "https://api.fortnox.se/3"; + + /// + /// Timeout for getting response. Default value is 30 seconds + /// + public static int Timeout { get; set; } = 30 * 10000; } } \ No newline at end of file