From 74424edc8956fef5a31b3bef239e42789a158f4f Mon Sep 17 00:00:00 2001 From: Ske Date: Mon, 8 Feb 2021 19:53:06 +0100 Subject: [PATCH] Refactor rate limit parser, fix locale also --- .../Rest/Ratelimit/DiscordRateLimitPolicy.cs | 2 +- Myriad/Rest/Ratelimit/RatelimitHeaders.cs | 108 ++++++++++++------ 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/Myriad/Rest/Ratelimit/DiscordRateLimitPolicy.cs b/Myriad/Rest/Ratelimit/DiscordRateLimitPolicy.cs index 9c9e2d00..0ec340e1 100644 --- a/Myriad/Rest/Ratelimit/DiscordRateLimitPolicy.cs +++ b/Myriad/Rest/Ratelimit/DiscordRateLimitPolicy.cs @@ -37,7 +37,7 @@ namespace Myriad.Rest.Ratelimit var response = await action(context, ct).ConfigureAwait(continueOnCapturedContext); // Update rate limit state with headers - var headers = new RatelimitHeaders(response); + var headers = RatelimitHeaders.Parse(response); _ratelimiter.HandleResponse(headers, endpoint, major); return response; diff --git a/Myriad/Rest/Ratelimit/RatelimitHeaders.cs b/Myriad/Rest/Ratelimit/RatelimitHeaders.cs index 5387a10a..581b360e 100644 --- a/Myriad/Rest/Ratelimit/RatelimitHeaders.cs +++ b/Myriad/Rest/Ratelimit/RatelimitHeaders.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Linq; using System.Net.Http; @@ -6,46 +7,79 @@ namespace Myriad.Rest.Ratelimit { public record RatelimitHeaders { - public RatelimitHeaders() { } + private const string LimitHeader = "X-RateLimit-Limit"; + private const string RemainingHeader = "X-RateLimit-Remaining"; + private const string ResetHeader = "X-RateLimit-Reset"; + private const string ResetAfterHeader = "X-RateLimit-Reset-After"; + private const string BucketHeader = "X-RateLimit-Bucket"; + private const string GlobalHeader = "X-RateLimit-Global"; + + public bool Global { get; private set; } + public int? Limit { get; private set; } + public int? Remaining { get; private set; } + public DateTimeOffset? Reset { get; private set; } + public TimeSpan? ResetAfter { get; private set; } + public string? Bucket { get; private set; } - public RatelimitHeaders(HttpResponseMessage response) - { - ServerDate = response.Headers.Date; - - if (response.Headers.TryGetValues("X-RateLimit-Limit", out var limit)) - if (int.TryParse(limit.First(), out var limitNum)) - Limit = limitNum; - - if (response.Headers.TryGetValues("X-RateLimit-Remaining", out var remaining)) - if (int.TryParse(remaining!.First(), out var remainingNum)) - Remaining = remainingNum; - - if (response.Headers.TryGetValues("X-RateLimit-Reset", out var reset)) - if (double.TryParse(reset!.First(), out var resetNum)) - Reset = DateTimeOffset.FromUnixTimeMilliseconds((long) (resetNum * 1000)); - - if (response.Headers.TryGetValues("X-RateLimit-Reset-After", out var resetAfter)) - if (double.TryParse(resetAfter!.First(), out var resetAfterNum)) - ResetAfter = TimeSpan.FromSeconds(resetAfterNum); - - if (response.Headers.TryGetValues("X-RateLimit-Bucket", out var bucket)) - Bucket = bucket.First(); - - if (response.Headers.TryGetValues("X-RateLimit-Global", out var global)) - if (bool.TryParse(global!.First(), out var globalBool)) - Global = globalBool; - } - - public bool Global { get; init; } - public int? Limit { get; init; } - public int? Remaining { get; init; } - public DateTimeOffset? Reset { get; init; } - public TimeSpan? ResetAfter { get; init; } - public string? Bucket { get; init; } - - public DateTimeOffset? ServerDate { get; init; } + public DateTimeOffset? ServerDate { get; private set; } public bool HasRatelimitInfo => Limit != null && Remaining != null && Reset != null && ResetAfter != null && Bucket != null; + + public RatelimitHeaders() { } + + public static RatelimitHeaders Parse(HttpResponseMessage response) + { + var headers = new RatelimitHeaders + { + ServerDate = response.Headers.Date, + Limit = TryGetInt(response, LimitHeader), + Remaining = TryGetInt(response, RemainingHeader), + Bucket = TryGetHeader(response, BucketHeader) + }; + + + var resetTimestamp = TryGetDouble(response, ResetHeader); + if (resetTimestamp != null) + headers.Reset = DateTimeOffset.FromUnixTimeMilliseconds((long) (resetTimestamp.Value * 1000)); + + var resetAfterSeconds = TryGetDouble(response, ResetAfterHeader); + if (resetAfterSeconds != null) + headers.ResetAfter = TimeSpan.FromSeconds(resetAfterSeconds.Value); + + var global = TryGetHeader(response, GlobalHeader); + if (global != null && bool.TryParse(global, out var globalBool)) + headers.Global = globalBool; + + return headers; + } + + private static string? TryGetHeader(HttpResponseMessage response, string headerName) + { + if (!response.Headers.TryGetValues(headerName, out var values)) + return null; + + return values.FirstOrDefault(); + } + + private static int? TryGetInt(HttpResponseMessage response, string headerName) + { + var valueString = TryGetHeader(response, headerName); + + if (!int.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) + return null; + + return value; + } + + private static double? TryGetDouble(HttpResponseMessage response, string headerName) + { + var valueString = TryGetHeader(response, headerName); + + if (!double.TryParse(valueString, NumberStyles.Float, CultureInfo.InvariantCulture, out var value)) + return null; + + return value; + } } } \ No newline at end of file