public async Task <Stream> SendAsync(RestRequest request) { int id = Interlocked.Increment(ref nextId); #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Start"); #endif LastAttemptAt = DateTimeOffset.UtcNow; while (true) { await _queue.EnterGlobalAsync(id, request).ConfigureAwait(false); await EnterAsync(id, request).ConfigureAwait(false); if (_redirectBucket != null) { return(await _redirectBucket.SendAsync(request)); } #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Sending..."); #endif RateLimitInfo info = default(RateLimitInfo); try { var response = await request.SendAsync().ConfigureAwait(false); info = new RateLimitInfo(response.Headers); if (response.StatusCode < (HttpStatusCode)200 || response.StatusCode >= (HttpStatusCode)300) { switch (response.StatusCode) { case (HttpStatusCode)429: if (info.IsGlobal) { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 429 [Global]"); #endif _queue.PauseGlobal(info); } else { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 429"); #endif UpdateRateLimit(id, request, info, true); } await _queue.RaiseRateLimitTriggered(Id, info, $"{request.Method} {request.Endpoint}").ConfigureAwait(false); continue; //Retry case HttpStatusCode.BadGateway: //502 #if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 502"); #endif if ((request.Options.RetryMode & RetryMode.Retry502) == 0) { throw new HttpException(HttpStatusCode.BadGateway, request, null); } continue; //Retry default: int? code = null; string reason = null; if (response.Stream != null) { try { using (var reader = new StreamReader(response.Stream)) using (var jsonReader = new JsonTextReader(reader)) { try { var json = await JToken.LoadAsync(jsonReader).ConfigureAwait(false); try { code = json.Value <int>("code"); } catch { } try { reason = json.Value <string>("message"); } catch { } } catch { if (response.StatusCode == HttpStatusCode.RequestEntityTooLarge) { code = 40005; reason = "The server responded with error 40005: Request entity too large"; } else { code = (int)response.StatusCode; if (response.Stream is MemoryStream ms) { reason = Encoding.UTF8.GetString(ms.ToArray()); } } } } } catch { } } throw new HttpException(response.StatusCode, request, code, reason); } } else { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Success"); #endif return(response.Stream); } } //catch (HttpException) { throw; } //Pass through catch (TimeoutException) { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Timeout"); #endif if ((request.Options.RetryMode & RetryMode.RetryTimeouts) == 0) { throw; } await Task.Delay(500).ConfigureAwait(false); continue; //Retry } /*catch (Exception) * { #if DEBUG_LIMITS * Debug.WriteLine($"[{id}] Error"); #endif * if ((request.Options.RetryMode & RetryMode.RetryErrors) == 0) * throw; * * await Task.Delay(500); * continue; //Retry * }*/ finally { UpdateRateLimit(id, request, info, false); #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Stop"); #endif } } }
public async Task <Stream> SendAsync(RestRequest request) { int id = Interlocked.Increment(ref nextId); #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Start"); #endif LastAttemptAt = DateTimeOffset.UtcNow; while (true) { await _queue.EnterGlobalAsync(id, request).ConfigureAwait(false); await EnterAsync(id, request).ConfigureAwait(false); if (_redirectBucket != null) { return(await _redirectBucket.SendAsync(request)); } #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Sending..."); #endif RateLimitInfo info = default(RateLimitInfo); try { var response = await request.SendAsync().ConfigureAwait(false); info = new RateLimitInfo(response.Headers, request.Endpoint); request.Options.ExecuteRatelimitCallback(info); if (response.StatusCode < (HttpStatusCode)200 || response.StatusCode >= (HttpStatusCode)300) { switch (response.StatusCode) { case (HttpStatusCode)429: if (info.IsGlobal) { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 429 [Global]"); #endif _queue.PauseGlobal(info); } else { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 429"); #endif UpdateRateLimit(id, request, info, true, body: response.Stream); } await _queue.RaiseRateLimitTriggered(Id, info, $"{request.Method} {request.Endpoint}").ConfigureAwait(false); continue; //Retry case HttpStatusCode.BadGateway: //502 #if DEBUG_LIMITS Debug.WriteLine($"[{id}] (!) 502"); #endif if ((request.Options.RetryMode & RetryMode.Retry502) == 0) { throw new HttpException(HttpStatusCode.BadGateway, request, null); } continue; //Retry default: API.DiscordError error = null; if (response.Stream != null) { try { using var reader = new StreamReader(response.Stream); using var jsonReader = new JsonTextReader(reader); error = Discord.Rest.DiscordRestClient.Serializer.Deserialize <API.DiscordError>(jsonReader); } catch { } } throw new HttpException( response.StatusCode, request, error?.Code, error?.Message, error?.Errors.IsSpecified == true ? error.Errors.Value.Select(x => new DiscordJsonError(x.Name.GetValueOrDefault("root"), x.Errors.Select(y => new DiscordError(y.Code, y.Message)).ToArray())).ToArray() : null ); } } else { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Success"); #endif return(response.Stream); } } //catch (HttpException) { throw; } //Pass through catch (TimeoutException) { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Timeout"); #endif if ((request.Options.RetryMode & RetryMode.RetryTimeouts) == 0) { throw; } await Task.Delay(500).ConfigureAwait(false); continue; //Retry } /*catch (Exception) * { #if DEBUG_LIMITS * Debug.WriteLine($"[{id}] Error"); #endif * if ((request.Options.RetryMode & RetryMode.RetryErrors) == 0) * throw; * * await Task.Delay(500); * continue; //Retry * }*/ finally { UpdateRateLimit(id, request, info, false); #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Stop"); #endif } } }