Browse Source

feature: Add support for setting X-RateLimit-Precision (#1354)

* support X-RateLimit-Reset sending integer or float values

This changes the way that the X-RateLimit-Request header is parsed, so that it will work with both integer seconds and float values with seconds and milliseconds

* Add RateLimitPrecision enum, set X-RateLimit-Precision

Adds the RateLimitPrecision enum, with Second and Millisecond values. (Do we want to use an extension method to convert it into a string, or is ToString().ToLower() fine?)
Adds RateLimitPrecision as a parameter to DiscordRestApiClient, and to DiscordConfig so that it can set the X-RateLimit-Precision header.
tags/2.2.0
Chris Johnston Christopher F 5 years ago
parent
commit
9482204bcf
8 changed files with 47 additions and 10 deletions
  1. +14
    -2
      src/Discord.Net.Core/DiscordConfig.cs
  2. +18
    -0
      src/Discord.Net.Core/RateLimitPrecision.cs
  3. +5
    -2
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  4. +1
    -1
      src/Discord.Net.Rest/Net/RateLimitInfo.cs
  5. +2
    -1
      src/Discord.Net.WebSocket/BaseSocketClient.cs
  6. +2
    -1
      src/Discord.Net.WebSocket/DiscordShardedClient.cs
  7. +3
    -2
      src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
  8. +2
    -1
      src/Discord.Net.WebSocket/DiscordSocketClient.cs

+ 14
- 2
src/Discord.Net.Core/DiscordConfig.cs View File

@@ -36,7 +36,7 @@ namespace Discord
typeof(DiscordConfig).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ??
typeof(DiscordConfig).GetTypeInfo().Assembly.GetName().Version.ToString(3) ??
"Unknown";
/// <summary>
/// Gets the user agent that Discord.Net uses in its clients.
/// </summary>
@@ -123,7 +123,7 @@ namespace Discord
/// The currently set <see cref="RetryMode"/>.
/// </returns>
public RetryMode DefaultRetryMode { get; set; } = RetryMode.AlwaysRetry;
/// <summary>
/// Gets or sets the minimum log level severity that will be sent to the Log event.
/// </summary>
@@ -140,5 +140,17 @@ namespace Discord
/// the API version it uses on startup.
/// </remarks>
internal bool DisplayInitialLog { get; set; } = true;

/// <summary>
/// Gets or sets the level of precision of the rate limit reset response.
/// </summary>
/// <remarks>
/// If set to <see cref="RateLimitPrecision.Second"/>, this value will be rounded up to the
/// nearest second.
/// </remarks>
/// <returns>
/// The currently set <see cref="RateLimitPrecision"/>.
/// </returns>
public RateLimitPrecision RateLimitPrecision { get; set; } = RateLimitPrecision.Second;
}
}

+ 18
- 0
src/Discord.Net.Core/RateLimitPrecision.cs View File

@@ -0,0 +1,18 @@
namespace Discord
{
/// <summary>
/// Specifies the level of precision to request in the rate limit
/// response header.
/// </summary>
public enum RateLimitPrecision
{
/// <summary>
/// Specifies precision rounded up to the nearest whole second
/// </summary>
Second,
/// <summary>
/// Specifies precision rounded to the nearest millisecond.
/// </summary>
Millisecond
}
}

+ 5
- 2
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -45,17 +45,19 @@ namespace Discord.API
internal string AuthToken { get; private set; }
internal IRestClient RestClient { get; private set; }
internal ulong? CurrentUserId { get; set; }

public RateLimitPrecision RateLimitPrecision { get; private set; }
internal JsonSerializer Serializer => _serializer;

/// <exception cref="ArgumentException">Unknown OAuth token type.</exception>
public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry,
JsonSerializer serializer = null)
JsonSerializer serializer = null, RateLimitPrecision rateLimitPrecision = RateLimitPrecision.Second)
{
_restClientProvider = restClientProvider;
UserAgent = userAgent;
DefaultRetryMode = defaultRetryMode;
_serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver() };
RateLimitPrecision = rateLimitPrecision;

RequestQueue = new RequestQueue();
_stateLock = new SemaphoreSlim(1, 1);
@@ -71,6 +73,7 @@ namespace Discord.API
RestClient.SetHeader("accept", "*/*");
RestClient.SetHeader("user-agent", UserAgent);
RestClient.SetHeader("authorization", GetPrefixedToken(AuthTokenType, AuthToken));
RestClient.SetHeader("X-RateLimit-Precision", RateLimitPrecision.ToString().ToLower());
}
/// <exception cref="ArgumentException">Unknown OAuth token type.</exception>
internal static string GetPrefixedToken(TokenType tokenType, string token)


+ 1
- 1
src/Discord.Net.Rest/Net/RateLimitInfo.cs View File

@@ -21,7 +21,7 @@ namespace Discord.Net
Remaining = headers.TryGetValue("X-RateLimit-Remaining", out temp) &&
int.TryParse(temp, out var remaining) ? remaining : (int?)null;
Reset = headers.TryGetValue("X-RateLimit-Reset", out temp) &&
int.TryParse(temp, out var reset) ? DateTimeOffset.FromUnixTimeSeconds(reset) : (DateTimeOffset?)null;
float.TryParse(temp, out var reset) ? DateTimeOffset.FromUnixTimeMilliseconds((long)(reset * 1000)) : (DateTimeOffset?)null;
RetryAfter = headers.TryGetValue("Retry-After", out temp) &&
int.TryParse(temp, out var retryAfter) ? retryAfter : (int?)null;
Lag = headers.TryGetValue("Date", out temp) &&


+ 2
- 1
src/Discord.Net.WebSocket/BaseSocketClient.cs View File

@@ -80,7 +80,8 @@ namespace Discord.WebSocket
internal BaseSocketClient(DiscordSocketConfig config, DiscordRestApiClient client)
: base(config, client) => BaseConfig = config;
private static DiscordSocketApiClient CreateApiClient(DiscordSocketConfig config)
=> new DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent);
=> new DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent,
rateLimitPrecision: config.RateLimitPrecision);

/// <summary>
/// Gets a Discord application information for the logged-in user.


+ 2
- 1
src/Discord.Net.WebSocket/DiscordShardedClient.cs View File

@@ -85,7 +85,8 @@ namespace Discord.WebSocket
}
}
private static API.DiscordSocketApiClient CreateApiClient(DiscordSocketConfig config)
=> new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent);
=> new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent,
rateLimitPrecision: config.RateLimitPrecision);

internal override async Task OnLoginAsync(TokenType tokenType, string token)
{


+ 3
- 2
src/Discord.Net.WebSocket/DiscordSocketApiClient.cs View File

@@ -38,8 +38,9 @@ namespace Discord.API
public ConnectionState ConnectionState { get; private set; }

public DiscordSocketApiClient(RestClientProvider restClientProvider, WebSocketProvider webSocketProvider, string userAgent,
string url = null, RetryMode defaultRetryMode = RetryMode.AlwaysRetry, JsonSerializer serializer = null)
: base(restClientProvider, userAgent, defaultRetryMode, serializer)
string url = null, RetryMode defaultRetryMode = RetryMode.AlwaysRetry, JsonSerializer serializer = null,
RateLimitPrecision rateLimitPrecision = RateLimitPrecision.Second)
: base(restClientProvider, userAgent, defaultRetryMode, serializer, rateLimitPrecision)
{
_gatewayUrl = url;
if (url != null)


+ 2
- 1
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -176,7 +176,8 @@ namespace Discord.WebSocket
_largeGuilds = new ConcurrentQueue<ulong>();
}
private static API.DiscordSocketApiClient CreateApiClient(DiscordSocketConfig config)
=> new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent, config.GatewayHost);
=> new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent, config.GatewayHost,
rateLimitPrecision: config.RateLimitPrecision);
/// <inheritdoc />
internal override void Dispose(bool disposing)
{


Loading…
Cancel
Save