Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for setting X-RateLimit-Precision #1354

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/Discord.Net.Core/DiscordConfig.cs
Expand Up @@ -36,7 +36,7 @@ public class DiscordConfig
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>
Expand Down Expand Up @@ -123,7 +123,7 @@ public class DiscordConfig
/// 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>
Expand All @@ -140,5 +140,17 @@ public class DiscordConfig
/// 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 changes: 18 additions & 0 deletions src/Discord.Net.Core/RateLimitPrecision.cs
@@ -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
}
}
7 changes: 5 additions & 2 deletions src/Discord.Net.Rest/DiscordRestApiClient.cs
Expand Up @@ -45,17 +45,19 @@ internal class DiscordRestApiClient : IDisposable
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);
Expand All @@ -71,6 +73,7 @@ internal void SetBaseUrl(string baseUrl)
RestClient.SetHeader("accept", "*/*");
RestClient.SetHeader("user-agent", UserAgent);
RestClient.SetHeader("authorization", GetPrefixedToken(AuthTokenType, AuthToken));
RestClient.SetHeader("X-RateLimit-Precision", RateLimitPrecision.ToString().ToLower());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this conversion only occurs here at the moment, I am alright with it remaining as ToString().ToLower() - however, if in the future we decide (for some reason) to allow this on a per-request basis, we should definitely move to an extension method, a la RateLimitPrecision.AsHeaderValue()

}
/// <exception cref="ArgumentException">Unknown OAuth token type.</exception>
internal static string GetPrefixedToken(TokenType tokenType, string token)
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Rest/Net/RateLimitInfo.cs
Expand Up @@ -21,7 +21,7 @@ internal RateLimitInfo(Dictionary<string, string> headers)
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) &&
Expand Down
3 changes: 2 additions & 1 deletion src/Discord.Net.WebSocket/BaseSocketClient.cs
Expand Up @@ -80,7 +80,8 @@ public abstract partial class BaseSocketClient : BaseDiscordClient, IDiscordClie
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.
Expand Down
3 changes: 2 additions & 1 deletion src/Discord.Net.WebSocket/DiscordShardedClient.cs
Expand Up @@ -85,7 +85,8 @@ private DiscordShardedClient(int[] ids, DiscordSocketConfig config, API.DiscordS
}
}
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)
{
Expand Down
5 changes: 3 additions & 2 deletions src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
Expand Up @@ -38,8 +38,9 @@ internal class DiscordSocketApiClient : DiscordRestApiClient
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)
Expand Down
3 changes: 2 additions & 1 deletion src/Discord.Net.WebSocket/DiscordSocketClient.cs
Expand Up @@ -176,7 +176,8 @@ private DiscordSocketClient(DiscordSocketConfig config, API.DiscordSocketApiClie
_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)
{
Expand Down