private async Task <Videos> GetVideosEndpoint(int offset, int retry) { await RateLimit.WaitAsync(); var rateLimitTask = StartRatelimit(); try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("User-Agent", "KiteBotCore 1.1 GB Discord Bot for fetching wiki information"); return(JsonConvert.DeserializeObject <Videos>(await client.GetStringAsync($@"{_apiCallUrl}&offset={offset}"))); } } catch (Exception) { if (++retry < 3) { await Task.Delay(5000); await rateLimitTask; return(await GetVideosEndpoint(offset, retry)); } throw new TimeoutException(); } }
public void GetRateLimits(string mess) { var rateLimits = RateLimit.GetCurrentCredentialsRateLimits(); if (rateLimits != null) { try { var currentUser = User.GetLoggedUser().Name; FOutputStatus[0] = "F**k YEAH! Logged in as " + currentUser; FLogger.Log(LogType.Debug, "F**k YEAH! Logged in as " + currentUser); FOutputSearchesRemaining[0] = rateLimits.SearchTweetsLimit.Limit; FOutputSearchesReset[0] = rateLimits.SearchTweetsLimit.ResetDateTime.ToString(); FOutputStatusBool[0] = true; loggedIn = true; } catch { FOutputStatus[0] = mess; FLogger.Log(LogType.Debug, mess); ClearOutputPins(); FOutputStatusBool[0] = false; loggedIn = false; } } else { FOutputStatus[0] = mess; FLogger.Log(LogType.Debug, mess); ClearOutputPins(); FOutputStatusBool[0] = false; loggedIn = false; } }
public void CanPopulateObjectFromSerializedData() { var headers = new Dictionary<string, string> { { "X-RateLimit-Limit", "100" }, { "X-RateLimit-Remaining", "42" }, { "X-RateLimit-Reset", "1372700873" } }; var rateLimit = new RateLimit(headers); using (var stream = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(stream, rateLimit); stream.Position = 0; var deserialized = (RateLimit)formatter.Deserialize(stream); Assert.Equal(100, deserialized.Limit); Assert.Equal(42, deserialized.Remaining); var expectedReset = DateTimeOffset.ParseExact( "Mon 01 Jul 2013 5:47:53 PM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); Assert.Equal(expectedReset, deserialized.Reset); } }
private async Task <GameResult> GetGameEndpoint(int gameId, int retry) { await RateLimit.WaitAsync().ConfigureAwait(false); var rateLimitTask = StartRatelimit(); try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("User-Agent", "KiteBotCore 1.1 GB Discord Bot for fetching wiki information"); return(JsonConvert.DeserializeObject <GameResult>(await client.GetStringAsync(_gameAPIUrl(gameId)) .ConfigureAwait(false))); } } catch (TimeoutException timeoutEx) { Log.Debug(timeoutEx, timeoutEx.Message); if (retry > 0) { await Task.Delay(2000).ConfigureAwait(false); await rateLimitTask.ConfigureAwait(false); return(await GetGameEndpoint(gameId, retry - 1).ConfigureAwait(false)); } throw; } }
public static void Postfix(RateLimit __instance, ref bool __result) { if (__result == false) { Log.Debug($"[RateLimitPatch] {__instance._usagesAllowed}:{__instance._timeWindow}"); } }
private readonly RateLimiter _privateApiRateLimiter; // Nullable. /// <summary> /// Initializes a new instance of the <see cref="KrakenClient"/> class. /// </summary> /// <param name="apiKey">Key required to make private queries to the API.</param> /// <param name="privateKey">Secret required to sign private messages.</param> /// <param name="rateLimit"> /// Used to enable API call rate limiter conforming to Kraken rules. To disable, use <see cref="RateLimit.None"/>. /// </param> public KrakenClient( string apiUrl, string apiKey, string privateKey, RateLimit rateLimit = RateLimit.None) { if (apiKey == null) { throw new ArgumentNullException(nameof(apiKey)); } if (privateKey == null) { throw new ArgumentNullException(nameof(privateKey)); } ApiKey = apiKey; PrivateKey = privateKey; RateLimit = rateLimit; TierInfo info = null; if (TierInfo.TryGetValue(rateLimit, out info)) { _privateApiRateLimiter = new RateLimiter(info.Limit, info.DecreaseTime, new Stopwatch()); // If private rate limiter enabled, also enable public rate limiter. _publicApiRateLimiter = new RateLimiter(20, TimeSpan.FromSeconds(1), new Stopwatch()); } _httpClient.BaseAddress = new Uri(apiUrl); _sha512PrivateKey = new HMACSHA512(Convert.FromBase64String(privateKey)); }
public void CanPopulateObjectFromSerializedData() { var headers = new Dictionary <string, string> { { "X-RateLimit-Limit", "100" }, { "X-RateLimit-Remaining", "42" }, { "X-RateLimit-Reset", "1372700873" } }; var rateLimit = new RateLimit(headers); using (var stream = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(stream, rateLimit); stream.Position = 0; var deserialized = (RateLimit)formatter.Deserialize(stream); Assert.Equal(100, deserialized.Limit); Assert.Equal(42, deserialized.Remaining); var expectedReset = DateTimeOffset.ParseExact( "Mon 01 Jul 2013 5:47:53 PM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); Assert.Equal(expectedReset, deserialized.Reset); } }
public override TimeSpan CalcReloadTime(RateLimit rateLimit) { var currentTime = DateTimeOffset.Now.ToUniversalTime(); var remainingTime = rateLimit.Reset - currentTime; // 切り捨てたいからint/intでシンプルに var totalRemaining = rateLimit.Remaining / CntTabs; if (totalRemaining == 0) { if (TimeSpan.Zero < (rateLimit.Reset - DateTimeOffset.Now)) { return(CompareMinReloadTime(remainingTime.Add(TimeSpan.FromSeconds(1.5d)))); } else { var limitDictionary = Authorization.GetToken().Application.RateLimitStatus("statuses").GetValueOrDefault("statuses"); if (limitDictionary.TryGetValue("/statuses/home_timeline", out var limit)) { return(CompareMinReloadTime(CalcReloadTime(limit))); } } } else if (totalRemaining <= Buffer) { return(CompareMinReloadTime(TimeSpan.FromTicks(remainingTime.Ticks / totalRemaining))); } return(CompareMinReloadTime(TimeSpan.FromTicks(remainingTime.Ticks / (totalRemaining - Buffer)))); }
public void GetDelayTest() { var limit = new RateLimit(); // Test passing 0 for the request per hour. Assert.AreEqual(0, limit.GetDelay(0)); // No web calls yet. Assert.AreEqual(0, limit.GetDelay(2000)); // Test being under the limit. limit.AddApiCall(); Thread.Sleep(500); limit.AddApiCall(); Assert.AreEqual(0, limit.GetDelay(2000)); // Test being over the limit. Thread.Sleep(500); limit.AddApiCall(); Thread.Sleep(500); limit.AddApiCall(); Thread.Sleep(500); limit.AddApiCall(); Thread.Sleep(500); limit.AddApiCall(); Assert.AreNotEqual(0, limit.GetDelay(2000)); }
public void ContructerTest() { var limit = new RateLimit(); var privateObject = new PrivateObject(limit); Assert.IsNotNull(privateObject.GetFieldOrProperty("_webServiceCalls")); }
private async Task <Search> GetSearchEndpoint(string gameTitle, int retry) { await RateLimit.WaitAsync().ConfigureAwait(false); var rateLimitTask = StartRatelimit(); try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("User-Agent", "KiteBotCore 1.1 GB Discord Bot for fetching wiki information"); return(JsonConvert.DeserializeObject <Search>(await client.GetStringAsync(Uri.EscapeUriString($@"{_searchAPIUrl}""{gameTitle}""")).ConfigureAwait(false))); } } catch (Exception) { if (retry > 0) { await Task.Delay(2000).ConfigureAwait(false); await rateLimitTask.ConfigureAwait(false); return(await GetSearchEndpoint(gameTitle, retry - 1).ConfigureAwait(false)); } throw new TimeoutException(); } }
static void PrintRateLimitInfo(RateLimit limit) { var percentLeft = 100 * limit.Remaining / limit.Limit; if (percentLeft <= 25) { Console.ForegroundColor = ConsoleColor.Red; } else if (percentLeft <= 50) { Console.ForegroundColor = ConsoleColor.Yellow; } else { Console.ForegroundColor = ConsoleColor.Green; } Console.Write($"{limit.Remaining} ({percentLeft}%)"); Console.ResetColor(); Console.Write(" API calls remaining out of " + limit.Limit + ", resetting on "); Console.ForegroundColor = ConsoleColor.DarkCyan; Console.WriteLine(limit.Reset.ToLocalTime().ToString("f")); Console.ResetColor(); }
public static void ResetRateLimit() { _semaphoreSlim.Wait(); _apiRateLimit = new RateLimit(); _semaphoreSlim.Release(); }
public static void RateLimits_ManualAwait() { TweetinviEvents.QueryBeforeExecute += (sender, args) => { var queryRateLimit = RateLimit.GetQueryRateLimit(args.QueryURL); RateLimit.AwaitForQueryRateLimit(queryRateLimit); }; }
private async Task CreatePersonGroup(string groupId) { await RateLimit.Perform(async() => { await Client.LargePersonGroup.CreateAsync(groupId, groupId); await Console.Error.WriteLineAsync($"Created person group {groupId}"); }); }
public static void GetCurrentCredentialsRateLimits() { var tokenRateLimits = RateLimit.GetCurrentCredentialsRateLimits(); Console.WriteLine("Remaning Requests for GetRate : {0}", tokenRateLimits.ApplicationRateLimitStatusLimit.Remaining); Console.WriteLine("Total Requests Allowed for GetRate : {0}", tokenRateLimits.ApplicationRateLimitStatusLimit.Limit); Console.WriteLine("GetRate limits will reset at : {0} local time", tokenRateLimits.ApplicationRateLimitStatusLimit.ResetDateTime.ToString("T")); }
/// <summary> /// Make a request to a path on the API /// </summary> /// <param name="url">Path and query</param> /// <param name="baseUrl">Override the base url, null for the default BaseUrl</param> /// <param name="payload">Payload, can be null. For private API end points, the payload must contain a 'nonce' key with a string value, set to unix timestamp in milliseconds, or seconds with decimal depending on the API.</param> /// The encoding of payload is API dependant but is typically json.</param> /// <param name="method">Request method or null for default</param> /// <returns>Raw response</returns> public string MakeRequest(string url, string baseUrl = null, Dictionary <string, object> payload = null, string method = null) { RateLimit.WaitToProceed(); if (string.IsNullOrEmpty(url)) { return(null); } else if (url[0] != '/') { url = $"/{url}"; } string fullUrl = $"{(baseUrl ?? BaseUrl)}{url}"; Uri uri = ProcessRequestUrl(new UriBuilder(fullUrl), payload); // new Uri(fullUrl); // new Uri("https://api.gdax.com/products/BTC-EUR/candles?granularity=3600&start=2018-01-04T06%3A31%3A19&end=2018-01-04T08%3A31%3A19"); // HttpWebRequest request = HttpWebRequest.CreateHttp(uri); request.Method = method ?? RequestMethod; request.ContentType = RequestContentType; request.UserAgent = RequestUserAgent; request.CachePolicy = CachePolicy; request.Timeout = (int)RequestTimeout.TotalMilliseconds; request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; ProcessRequest(request, payload); HttpWebResponse response; try { response = request.GetResponse() as HttpWebResponse; if (response == null) { throw new APIException("Unknown response from server"); } } catch (WebException we) { response = we.Response as HttpWebResponse; if (response == null) { throw new APIException(we.Message ?? "Unknown response from server"); } } string responseString = null; using (Stream responseStream = response.GetResponseStream()) { responseString = new StreamReader(responseStream).ReadToEnd(); if (response.StatusCode != HttpStatusCode.OK) { throw new APIException(responseString); } ProcessResponse(response); } response.Dispose(); return(responseString); }
public RateGate(RateLimit rateLimit) { _timeUnitMilliseconds = (int)rateLimit.TimspSpan.TotalMilliseconds; _timeoutMilliseconds = (int)rateLimit.Timeout.TotalMilliseconds; _semaphore = new SemaphoreSlim(rateLimit.RequestCount, rateLimit.RequestCount); _exitTimes = new ConcurrentQueue <int>(); _exitTimer = new Timer(ExitTimerCallback, null, _timeUnitMilliseconds, Timeout.Infinite); }
private new Dictionary <string, object> GetNoncePayload() { RateLimit.WaitToProceed(); return(new Dictionary <string, object> { { "nonce", ((long)DateTime.UtcNow.UnixTimestampFromDateTimeMilliseconds()).ToString() }, { "recvWindow", 60000 } }); }
/// <summary> /// Make a request to a path on the API /// </summary> /// <param name="url">Path and query</param> /// <param name="baseUrl">Override the base url, null for the default BaseUrl</param> /// <param name="payload">Payload, can be null. For private API end points, the payload must contain a 'nonce' key set to GenerateNonce value.</param> /// The encoding of payload is API dependant but is typically json.</param> /// <param name="method">Request method or null for default</param> /// <returns>Raw response</returns> public string MakeRequest(string url, string baseUrl = null, Dictionary <string, object> payload = null, string method = null) { RateLimit.WaitToProceed(); if (string.IsNullOrWhiteSpace(url)) { return(null); } else if (url[0] != '/') { url = "/" + url; } string fullUrl = (baseUrl ?? BaseUrl) + url; Uri uri = ProcessRequestUrl(new UriBuilder(fullUrl), payload); HttpWebRequest request = HttpWebRequest.CreateHttp(uri); request.Headers["Accept-Language"] = "en-us; q=1.0;"; request.Method = method ?? RequestMethod; request.ContentType = RequestContentType; request.UserAgent = RequestUserAgent; request.CachePolicy = CachePolicy; request.Timeout = (int)RequestTimeout.TotalMilliseconds; request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; ProcessRequest(request, payload); HttpWebResponse response; try { response = request.GetResponse() as HttpWebResponse; if (response == null) { throw new APIException("Unknown response from server"); } } catch (WebException we) { response = we.Response as HttpWebResponse; if (response == null) { throw new APIException(we.Message ?? "Unknown response from server"); } } string responseString = null; using (Stream responseStream = response.GetResponseStream()) { responseString = new StreamReader(responseStream).ReadToEnd(); if (response.StatusCode != HttpStatusCode.OK) { throw new APIException(responseString); } ProcessResponse(response); } response.Dispose(); return(responseString); }
internal RateLimiter(RateLimit rateLimit, ILogger <IRateLimiter <T> >?logger) { this._serviceName = $"{typeof(RateLimiter<T>).Name}<{typeof(T).Name}>"; this.RateLimit = rateLimit; this.Logger = logger ?? NullLogger <RateLimiter <T> > .Instance; this._lastUpdateTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); this._availablePermits = rateLimit.AmountOfRequests; this._semaphoreSlim = new(1, 1); }
public void RateLimitsAreSetCorrectly() { var rateLimit = new RateLimit(1, TimeSpan.FromSeconds(1)); var rateLimiter = RateLimiter .WithRateLimit(rateLimit) .Build(); rateLimiter.GetRateLimit().Should().Be(rateLimit); }
private async Task <OperationResult <GatewayMessage> > RetryPostMessage(RateLimit rateLimit, string channelId, Message message) { var retryAfter = (int)rateLimit.RetryAfter * 1000; await Task.Delay(retryAfter); _logger.LogWarning("Retrying POST request after rate limit - {0}ms", retryAfter); return(await PostMessage(channelId, message)); }
private async Task <OperationResult <GatewayMessage> > RetryPutReaction(RateLimit rateLimit, string channelId, string messageId, Emoji emoji) { var retryAfter = (int)rateLimit.RetryAfter * 1000; await Task.Delay(retryAfter); _logger.LogWarning("Retrying PATCH request after rate limit - {0}ms", retryAfter); return(await AddReactionToMessage(channelId, messageId, emoji)); }
public RateGate(RateLimit rateLimit, IHaloSharpTimer timer) { _timeUnitMilliseconds = (int)rateLimit.TimeSpan.TotalMilliseconds; _timeoutMilliseconds = (int)rateLimit.Timeout.TotalMilliseconds; _semaphore = new SemaphoreSlim(rateLimit.RequestCount, rateLimit.RequestCount); _exitTimes = new ConcurrentQueue <int>(); timer.Setup(ExitTimerCallback, _timeUnitMilliseconds, Timeout.Infinite); _exitTimer = timer; //new HaloSharpTimer(ExitTimerCallback, null, _timeUnitMilliseconds, Timeout.Infinite); }
/// <summary> /// Make a JSON request to an API end point /// </summary> /// <typeparam name="T">Type of object to parse JSON as</typeparam> /// <param name="url">Path and query</param> /// <param name="baseUrl">Override the base url, null for the default BaseUrl</param> /// <param name="payload">Payload, can be null. For private API end points, the payload must contain a 'nonce' key with a string value, set to unix timestamp in milliseconds, or seconds with decimal depending on the API.</param> /// <param name="requestMethod">Request method or null for default</param> /// <returns>Result decoded from JSON response</returns> public T MakeJsonRequest <T>(string url, string baseUrl = null, Dictionary <string, object> payload = null, string requestMethod = null) { if (payload == null) { RateLimit.WaitToProceed(); } string response = MakeRequest(url, baseUrl, payload, requestMethod); return(JsonConvert.DeserializeObject <T>(response)); }
public async Task Delay_ZeroRequestsPerHour_NoDelay() { // arrange const int REQUESTS_PER_HOUR = 0; var rateLimit = new RateLimit(true); // act var result = await rateLimit.Delay(REQUESTS_PER_HOUR); Assert.Equal(0, result); }
public async Task Delay_TurnedOff_NoDelay() { // arrange const int REQUESTS_PER_HOUR = 10; var rateLimit = new RateLimit(false); // act var result = await rateLimit.Delay(REQUESTS_PER_HOUR); Assert.Equal(0, result); }
public void CanGetRateLimit() { var rateLimit = new RateLimit(1, TimeSpan.FromSeconds(1)); var rateLimiter = new RateLimiter <int>(new[] { new KeyValuePair <int, RateLimit>(1, rateLimit) }); rateLimiter.GetRateLimit(1).Should().Be(rateLimit); }
public RateLimitChangedNotification( RateLimit oldLocalRateLimit, RateLimit newLocalRateLimit, RateLimit oldGlobalRateLimit, RateLimit newGlobalRateLimit) { OldLocalRateLimit = oldLocalRateLimit; NewLocalRateLimit = newLocalRateLimit; OldGlobalRateLimit = oldGlobalRateLimit; NewGlobalRateLimit = newGlobalRateLimit; }
private async Task <IEnumerable <Person> > CreatePeople(string groupId, IEnumerable <string> names) { return(await Task.WhenAll(names.Select(name => RateLimit.Perform(async() => { var result = await Client.LargePersonGroupPerson.CreateAsync(groupId, name); await Console.Error.WriteLineAsync($"Created person {name}"); result.Name = name; return result; })))); }
public void HandlesMissingHeaderValues() { var headers = new Dictionary<string, string>(); var rateLimit = new RateLimit(headers); Assert.Equal(0, rateLimit.Limit); Assert.Equal(0, rateLimit.Remaining); var expectedReset = DateTimeOffset.ParseExact( "Thu 01 Jan 1970 0:00:00 AM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); Assert.Equal(expectedReset, rateLimit.Reset); }
public void ParsesRateLimitsFromHeaders() { var headers = new Dictionary<string, string> { { "X-RateLimit-Limit", "100" }, { "X-RateLimit-Remaining", "42" }, { "X-RateLimit-Reset", "1372700873" } }; var rateLimit = new RateLimit(headers); Assert.Equal(100, rateLimit.Limit); Assert.Equal(42, rateLimit.Remaining); var expectedReset = DateTimeOffset.ParseExact( "Mon 01 Jul 2013 5:47:53 PM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); Assert.Equal(expectedReset, rateLimit.Reset); }
public void HandlesInvalidHeaderValues() { var headers = new Dictionary<string, string> { { "X-RateLimit-Limit", "1234scoobysnacks1234" }, { "X-RateLimit-Remaining", "xanadu" }, { "X-RateLimit-Reset", "garbage" } }; var rateLimit = new RateLimit(headers); Assert.Equal(0, rateLimit.Limit); Assert.Equal(0, rateLimit.Remaining); var expectedReset = DateTimeOffset.ParseExact( "Thu 01 Jan 1970 0:00:00 AM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); Assert.Equal(expectedReset, rateLimit.Reset); }
/// <summary> /// Creates a new instance of the ApiInfo class. /// </summary> /// <param name="rateLimit">The current rate limit information.</param> public ApiInfo(RateLimit rateLimit) { RateLimit = rateLimit; }
public void CanClone() { var original = new RateLimit(100, 42, 1372700873); var clone = original.Clone(); // Note the use of Assert.NotSame tests for value types - this should continue to test should the underlying // model are changed to Object types Assert.NotSame(original, clone); Assert.Equal(original.Limit, clone.Limit); Assert.NotSame(original.Limit, clone.Limit); Assert.Equal(original.Remaining, clone.Remaining); Assert.NotSame(original.Remaining, clone.Remaining); Assert.Equal(original.ResetAsUtcEpochSeconds, clone.ResetAsUtcEpochSeconds); Assert.NotSame(original.ResetAsUtcEpochSeconds, clone.ResetAsUtcEpochSeconds); Assert.Equal(original.Reset, clone.Reset); Assert.NotSame(original.Reset, clone.Reset); }