private async Task _handleTooManyRequests(RateLimitInfo ratelimit) { _log(LogLevel.WARN, "Got 429 Response, this should normally not happen"); try { if (ratelimit.RetryAfter != null) { await Bucket.SetTimeout(TimeSpan.FromMilliseconds((int)ratelimit.RetryAfter)); _log(LogLevel.DEBUG, $"Timeout: {TimeSpan.FromMilliseconds((int) ratelimit.RetryAfter).TotalMilliseconds}"); } if (ratelimit.IsGlobal && ratelimit.RetryAfter != null && Client.GlobalTimeout == null) { await Bucket.SetGloballyLimited(TimeSpan.FromMilliseconds((int)ratelimit.RetryAfter)); _log(LogLevel.DEBUG, $"Global Limited: {TimeSpan.FromMilliseconds((int) ratelimit.RetryAfter).TotalMilliseconds}"); } Timeout = 100; } catch (Exception) { _log(LogLevel.WARN, $"Could not update Ratelimit information, retrying in {TimeSpan.FromMilliseconds(Timeout).TotalSeconds} Seconds"); Timeout *= 2; await Task.Delay(Timeout); await _handleTooManyRequests(ratelimit); } }
private async Task _handleHeaders(RateLimitInfo ratelimit) { _log(LogLevel.DEBUG, "Updating Bucket Ratelimit information"); try { if (ratelimit.Remaining != null) { await Bucket.SetRemaining((int)ratelimit.Remaining); _log(LogLevel.DEBUG, $"Remaining: {ratelimit.Remaining}"); } if (ratelimit.Limit != null) { await Bucket.SetLimit((int)ratelimit.Limit); _log(LogLevel.DEBUG, $"Limit: {ratelimit.Limit}"); } if (ratelimit.Reset != null) { await Bucket.SetTimeout( TimeSpan.FromMilliseconds(((DateTimeOffset)ratelimit.Reset - DateTimeOffset.UtcNow) .TotalMilliseconds)); _log(LogLevel.DEBUG, $"Reset: {TimeSpan.FromMilliseconds(((DateTimeOffset) ratelimit.Reset - DateTimeOffset.UtcNow).TotalMilliseconds)}"); } _log(LogLevel.DEBUG, "Updated Bucket Ratelimit information"); Timeout = 100; } catch (Exception) { Timeout *= 2; _log(LogLevel.WARN, $"Could not update Ratelimit information, retrying in {TimeSpan.FromMilliseconds(Timeout).TotalSeconds} Seconds"); await Task.Delay(Timeout); await _handleHeaders(ratelimit); } }
/// <summary> /// Executes this Request and Updates the Ratelimit information of the Bucket. /// </summary> /// <returns></returns> public async Task Execute() { HttpRequestMessage request; if (Method.Method == "GET") { Uri uri; try { uri = new UriBuilder($"{APIEndpoints.APIBaseURL}{URL}") { Query = Content != null?await((FormUrlEncodedContent)Content).ReadAsStringAsync() : null }.Uri; } catch (Exception e) { Error?.Invoke(this, e); return; } request = new HttpRequestMessage(Method, uri); } else { request = new HttpRequestMessage(Method, URL) { Content = Content }; } if (Reason != null) { request.Headers.Add("X-Audit-Log-Reason", HttpUtility.UrlEncode(Reason)); } HttpResponseMessage res; try { _log(LogLevel.DEBUG, "Sending Request..."); res = await Client.HttpClient.SendAsync(request); _log(LogLevel.DEBUG, $"Received Response {res.StatusCode}"); } catch (Exception e) { Error?.Invoke(this, e); return; } var ratelimit = new RateLimitInfo(res.Headers.ToDictionary(a => a.Key, a => a.Value.First())); _log(LogLevel.DEBUG, $"Created Ratelimit Info:\nLag: {ratelimit.Lag.TotalSeconds} Seconds\nLimit: {ratelimit.Limit}\nRemaining: {ratelimit.Remaining}\nReset: {ratelimit.Reset}\nGlobal Ratelimited: {ratelimit.IsGlobal}\nRetry-After: {ratelimit.RetryAfter}"); var statusCode = (int)res.StatusCode; string content; try { content = await res.Content.ReadAsStringAsync(); _log(LogLevel.DEBUG, "Parsed Content"); } catch (Exception e) { Error?.Invoke(this, e); return; } if (ratelimit.Limit != null && ratelimit.Remaining != null) { await _handleHeaders(ratelimit); } if (res.StatusCode == HttpStatusCode.TooManyRequests) { await _handleTooManyRequests(ratelimit); Bucket.Enqueue(this); } else if (statusCode >= 500 && statusCode < 600) { _internalServerError(); } else if (!res.IsSuccessStatusCode) { var error = JsonConvert.DeserializeObject <DiscordAPIErrorResponse>(content); Error?.Invoke(this, new DiscordAPIException(statusCode, error.Code, error.Message)); } else { Success?.Invoke(this, content); } }