| @@ -5,14 +5,36 @@ namespace Discord.Net | |||
| { | |||
| public class HttpException : Exception | |||
| { | |||
| public HttpStatusCode StatusCode { get; } | |||
| public HttpStatusCode HttpCode { get; } | |||
| public int? DiscordCode { get; } | |||
| public string Reason { get; } | |||
| public HttpException(HttpStatusCode statusCode, string reason = null) | |||
| : base($"The server responded with error {(int)statusCode} ({statusCode}){(reason != null ? $": \"{reason}\"" : "")}") | |||
| public HttpException(HttpStatusCode httpCode, int? discordCode = null, string reason = null) | |||
| : base(CreateMessage(httpCode, discordCode, reason)) | |||
| { | |||
| StatusCode = statusCode; | |||
| HttpCode = httpCode; | |||
| DiscordCode = discordCode; | |||
| Reason = reason; | |||
| } | |||
| private static string CreateMessage(HttpStatusCode httpCode, int? discordCode = null, string reason = null) | |||
| { | |||
| string msg; | |||
| if (discordCode != null) | |||
| { | |||
| if (reason != null) | |||
| msg = $"The server responded with error {(int)discordCode}: {reason}"; | |||
| else | |||
| msg = $"The server responded with error {(int)discordCode}: {httpCode}"; | |||
| } | |||
| else | |||
| { | |||
| if (reason != null) | |||
| msg = $"The server responded with error {(int)httpCode}: {reason}"; | |||
| else | |||
| msg = $"The server responded with error {(int)httpCode}: {httpCode}"; | |||
| } | |||
| return msg; | |||
| } | |||
| } | |||
| } | |||
| @@ -91,9 +91,9 @@ namespace Discord.Net.Queue | |||
| await Task.Delay(millis).ConfigureAwait(false); | |||
| } | |||
| } | |||
| internal void PauseGlobal(RateLimitInfo info, TimeSpan lag) | |||
| internal void PauseGlobal(RateLimitInfo info) | |||
| { | |||
| _waitUntil = DateTimeOffset.UtcNow.AddMilliseconds(info.RetryAfter.Value + lag.TotalMilliseconds); | |||
| _waitUntil = DateTimeOffset.UtcNow.AddMilliseconds(info.RetryAfter.Value + (info.Lag?.TotalMilliseconds ?? 0.0)); | |||
| } | |||
| private RequestBucket GetOrCreateBucket(string id, RestRequest request) | |||
| @@ -54,12 +54,10 @@ namespace Discord.Net.Queue | |||
| #if DEBUG_LIMITS | |||
| Debug.WriteLine($"[{id}] Sending..."); | |||
| #endif | |||
| TimeSpan lag = default(TimeSpan); | |||
| RateLimitInfo info = default(RateLimitInfo); | |||
| try | |||
| { | |||
| var response = await request.SendAsync().ConfigureAwait(false); | |||
| lag = DateTimeOffset.UtcNow - DateTimeOffset.Parse(response.Headers["Date"]); | |||
| info = new RateLimitInfo(response.Headers); | |||
| if (response.StatusCode < (HttpStatusCode)200 || response.StatusCode >= (HttpStatusCode)300) | |||
| @@ -72,14 +70,14 @@ namespace Discord.Net.Queue | |||
| #if DEBUG_LIMITS | |||
| Debug.WriteLine($"[{id}] (!) 429 [Global]"); | |||
| #endif | |||
| _queue.PauseGlobal(info, lag); | |||
| _queue.PauseGlobal(info); | |||
| } | |||
| else | |||
| { | |||
| #if DEBUG_LIMITS | |||
| Debug.WriteLine($"[{id}] (!) 429"); | |||
| #endif | |||
| UpdateRateLimit(id, request, info, lag, true); | |||
| UpdateRateLimit(id, request, info, true); | |||
| } | |||
| await _queue.RaiseRateLimitTriggered(Id, info).ConfigureAwait(false); | |||
| continue; //Retry | |||
| @@ -92,6 +90,7 @@ namespace Discord.Net.Queue | |||
| continue; //Retry | |||
| default: | |||
| int? code = null; | |||
| string reason = null; | |||
| if (response.Stream != null) | |||
| { | |||
| @@ -101,12 +100,13 @@ namespace Discord.Net.Queue | |||
| using (var jsonReader = new JsonTextReader(reader)) | |||
| { | |||
| var json = JToken.Load(jsonReader); | |||
| reason = json.Value<string>("message"); | |||
| try { code = json.Value<int>("code"); } catch { }; | |||
| try { reason = json.Value<string>("message"); } catch { }; | |||
| } | |||
| } | |||
| catch { } | |||
| } | |||
| throw new HttpException(response.StatusCode, reason); | |||
| throw new HttpException(response.StatusCode, code, reason); | |||
| } | |||
| } | |||
| else | |||
| @@ -142,7 +142,7 @@ namespace Discord.Net.Queue | |||
| }*/ | |||
| finally | |||
| { | |||
| UpdateRateLimit(id, request, info, lag, false); | |||
| UpdateRateLimit(id, request, info, false); | |||
| #if DEBUG_LIMITS | |||
| Debug.WriteLine($"[{id}] Stop"); | |||
| #endif | |||
| @@ -214,7 +214,7 @@ namespace Discord.Net.Queue | |||
| } | |||
| } | |||
| private void UpdateRateLimit(int id, RestRequest request, RateLimitInfo info, TimeSpan lag, bool is429) | |||
| private void UpdateRateLimit(int id, RestRequest request, RateLimitInfo info, bool is429) | |||
| { | |||
| if (WindowCount == 0) | |||
| return; | |||
| @@ -250,10 +250,10 @@ namespace Discord.Net.Queue | |||
| } | |||
| else if (info.Reset.HasValue) | |||
| { | |||
| resetTick = info.Reset.Value.AddSeconds(/*1.0 +*/ lag.TotalSeconds); | |||
| resetTick = info.Reset.Value.AddSeconds(info.Lag?.TotalSeconds ?? 1.0); | |||
| int diff = (int)(resetTick.Value - DateTimeOffset.UtcNow).TotalMilliseconds; | |||
| #if DEBUG_LIMITS | |||
| Debug.WriteLine($"[{id}] X-RateLimit-Reset: {info.Reset.Value.ToUnixTimeSeconds()} ({diff} ms, {lag.TotalMilliseconds} ms lag)"); | |||
| Debug.WriteLine($"[{id}] X-RateLimit-Reset: {info.Reset.Value.ToUnixTimeSeconds()} ({diff} ms, {info.Lag?.TotalMilliseconds} ms lag)"); | |||
| #endif | |||
| } | |||
| else if (request.Options.IsClientBucket && request.Options.BucketId != null) | |||
| @@ -10,6 +10,7 @@ namespace Discord.Net | |||
| public int? Remaining { get; } | |||
| public int? RetryAfter { get; } | |||
| public DateTimeOffset? Reset { get; } | |||
| public TimeSpan? Lag { get; } | |||
| internal RateLimitInfo(Dictionary<string, string> headers) | |||
| { | |||
| @@ -17,8 +18,11 @@ namespace Discord.Net | |||
| IsGlobal = headers.TryGetValue("X-RateLimit-Global", out temp) ? bool.Parse(temp) : false; | |||
| Limit = headers.TryGetValue("X-RateLimit-Limit", out temp) ? int.Parse(temp) : (int?)null; | |||
| Remaining = headers.TryGetValue("X-RateLimit-Remaining", out temp) ? int.Parse(temp) : (int?)null; | |||
| Reset = headers.TryGetValue("X-RateLimit-Reset", out temp) ? DateTimeUtils.FromUnixSeconds(int.Parse(temp)) : (DateTimeOffset?)null; | |||
| Reset = headers.TryGetValue("X-RateLimit-Reset", out temp) ? | |||
| DateTimeUtils.FromUnixSeconds(int.Parse(temp)) : (DateTimeOffset?)null; | |||
| RetryAfter = headers.TryGetValue("Retry-After", out temp) ? int.Parse(temp) : (int?)null; | |||
| Lag = headers.TryGetValue("Date", out temp) ? | |||
| DateTimeOffset.UtcNow - DateTimeOffset.Parse(temp) : (TimeSpan?)null; | |||
| } | |||
| } | |||
| } | |||