@@ -2504,9 +2504,8 @@ | |||
<param name="result">An emoji.</param> | |||
</member> | |||
<member name="M:Discord.Emoji.Parse(System.String)"> | |||
<summary> Parse an <see cref="T:Discord.Emoji"/> from its raw format. </summary> | |||
<param name="text">The raw encoding of an emoji. For example: <c>:heart: or ❤</c></param> | |||
<param name="result">An emoji.</param> | |||
<summary> Parse an <see cref="T:Discord.Emoji"/> from its raw format.</summary> | |||
<param name="emojiStr">The raw encoding of an emoji. For example: <c>:heart: or ❤</c></param> | |||
<exception cref="T:System.FormatException">String is not emoji or unicode!</exception> | |||
</member> | |||
<member name="M:Discord.Emoji.GetHashCode"> | |||
@@ -5040,6 +5039,14 @@ | |||
Whether this button is disabled or not. | |||
</summary> | |||
</member> | |||
<member name="M:Discord.ButtonComponent.ToBuilder"> | |||
<summary> | |||
Turns this button into a button builder. | |||
</summary> | |||
<returns> | |||
A newly created button builder with the same properties as this button. | |||
</returns> | |||
</member> | |||
<member name="T:Discord.ButtonStyle"> | |||
<summary> | |||
Represents different styles to use with buttons. You can see an example of the different styles at <see href="https://discord.com/developers/docs/interactions/message-components#buttons-button-styles"/> | |||
@@ -5746,6 +5753,14 @@ | |||
Whether this menu is disabled or not. | |||
</summary> | |||
</member> | |||
<member name="M:Discord.SelectMenu.ToBuilder"> | |||
<summary> | |||
Turns this select menu into a builder. | |||
</summary> | |||
<returns> | |||
A newly create builder with the same properties as this select menu. | |||
</returns> | |||
</member> | |||
<member name="T:Discord.SelectMenuOption"> | |||
<summary> | |||
Represents a choice for a <see cref="T:Discord.SelectMenu"/>. | |||
@@ -11813,6 +11828,56 @@ | |||
and an optional reason. | |||
</summary> | |||
</member> | |||
<member name="T:Discord.IRateLimitInfo"> | |||
<summary> | |||
Represents a generic ratelimit info. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.IsGlobal"> | |||
<summary> | |||
Gets whether or not this ratelimit info is global. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.Limit"> | |||
<summary> | |||
Gets the number of requests that can be made. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.Remaining"> | |||
<summary> | |||
Gets the number of remaining requests that can be made. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.RetryAfter"> | |||
<summary> | |||
Gets the total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.Reset"> | |||
<summary> | |||
Gets the <see cref="T:System.DateTimeOffset"/> at which the rate limit resets | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.ResetAfter"> | |||
<summary> | |||
Gets the absolute time when this ratelimit resets. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.Bucket"> | |||
<summary> | |||
Gets a unique string denoting the rate limit being encountered (non-inclusive of major parameters in the route path). | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.Lag"> | |||
<summary> | |||
Gets the amount of lag for the request. This is used to denote the precise time of when the ratelimit expires. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.IRateLimitInfo.Endpoint"> | |||
<summary> | |||
Gets the endpoint that this ratelimit info came from. | |||
</summary> | |||
</member> | |||
<member name="T:Discord.RequestOptions"> | |||
<summary> | |||
Represents options that should be used when sending a request. | |||
@@ -11870,6 +11935,11 @@ | |||
hosting system is known to have a desynced clock. | |||
</remarks> | |||
</member> | |||
<member name="P:Discord.RequestOptions.RatelimitCallback"> | |||
<summary> | |||
Gets or sets the callback to execute regarding ratelimits for this request. | |||
</summary> | |||
</member> | |||
<member name="M:Discord.RequestOptions.#ctor"> | |||
<summary> | |||
Initializes a new <see cref="T:Discord.RequestOptions" /> class with the default request timeout set in | |||
@@ -0,0 +1,59 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// Represents a generic ratelimit info. | |||
/// </summary> | |||
public interface IRateLimitInfo | |||
{ | |||
/// <summary> | |||
/// Gets whether or not this ratelimit info is global. | |||
/// </summary> | |||
bool IsGlobal { get; } | |||
/// <summary> | |||
/// Gets the number of requests that can be made. | |||
/// </summary> | |||
int? Limit { get; } | |||
/// <summary> | |||
/// Gets the number of remaining requests that can be made. | |||
/// </summary> | |||
int? Remaining { get; } | |||
/// <summary> | |||
/// Gets the total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision | |||
/// </summary> | |||
int? RetryAfter { get; } | |||
/// <summary> | |||
/// Gets the <see cref="DateTimeOffset"/> at which the rate limit resets | |||
/// </summary> | |||
DateTimeOffset? Reset { get; } | |||
/// <summary> | |||
/// Gets the absolute time when this ratelimit resets. | |||
/// </summary> | |||
TimeSpan? ResetAfter { get; } | |||
/// <summary> | |||
/// Gets a unique string denoting the rate limit being encountered (non-inclusive of major parameters in the route path). | |||
/// </summary> | |||
string Bucket { get; } | |||
/// <summary> | |||
/// Gets the amount of lag for the request. This is used to denote the precise time of when the ratelimit expires. | |||
/// </summary> | |||
TimeSpan? Lag { get; } | |||
/// <summary> | |||
/// Gets the endpoint that this ratelimit info came from. | |||
/// </summary> | |||
string Endpoint { get; } | |||
} | |||
} |
@@ -1,5 +1,7 @@ | |||
using Discord.Net; | |||
using System; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
@@ -57,6 +59,11 @@ namespace Discord | |||
/// </remarks> | |||
public bool? UseSystemClock { get; set; } | |||
/// <summary> | |||
/// Gets or sets the callback to execute regarding ratelimits for this request. | |||
/// </summary> | |||
public Func<IRateLimitInfo, Task> RatelimitCallback { get; set; } | |||
internal bool IgnoreState { get; set; } | |||
internal BucketId BucketId { get; set; } | |||
internal bool IsClientBucket { get; set; } | |||
@@ -71,6 +78,17 @@ namespace Discord | |||
return options.Clone(); | |||
} | |||
internal void ExecuteRatelimitCallback(IRateLimitInfo info) | |||
{ | |||
if (RatelimitCallback != null) | |||
{ | |||
_ = Task.Run(async () => | |||
{ | |||
await RatelimitCallback(info); | |||
}); | |||
} | |||
} | |||
/// <summary> | |||
/// Initializes a new <see cref="RequestOptions" /> class with the default request timeout set in | |||
/// <see cref="DiscordConfig"/>. | |||
@@ -149,6 +149,38 @@ | |||
<member name="M:Discord.Net.Converters.ImageConverter.ReadJson(Newtonsoft.Json.JsonReader,System.Type,System.Object,Newtonsoft.Json.JsonSerializer)"> | |||
<exception cref="T:System.InvalidOperationException">Cannot read from image.</exception> | |||
</member> | |||
<member name="T:Discord.Net.RateLimitInfo"> | |||
<summary> | |||
Represents a REST-Based ratelimit info. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.IsGlobal"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.Limit"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.Remaining"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.RetryAfter"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.Reset"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.ResetAfter"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.Bucket"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.Lag"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Net.RateLimitInfo.Endpoint"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.Rest.BaseDiscordClient.LoginState"> | |||
<summary> | |||
Gets the login state of the client. | |||
@@ -65,7 +65,9 @@ namespace Discord.Net.Queue | |||
try | |||
{ | |||
var response = await request.SendAsync().ConfigureAwait(false); | |||
info = new RateLimitInfo(response.Headers); | |||
info = new RateLimitInfo(response.Headers, request.Endpoint); | |||
request.Options.ExecuteRatelimitCallback(info); | |||
if (response.StatusCode < (HttpStatusCode)200 || response.StatusCode >= (HttpStatusCode)300) | |||
{ | |||
@@ -4,19 +4,42 @@ using System.Globalization; | |||
namespace Discord.Net | |||
{ | |||
internal struct RateLimitInfo | |||
/// <summary> | |||
/// Represents a REST-Based ratelimit info. | |||
/// </summary> | |||
public struct RateLimitInfo : IRateLimitInfo | |||
{ | |||
/// <inheritdoc/> | |||
public bool IsGlobal { get; } | |||
/// <inheritdoc/> | |||
public int? Limit { get; } | |||
/// <inheritdoc/> | |||
public int? Remaining { get; } | |||
/// <inheritdoc/> | |||
public int? RetryAfter { get; } | |||
/// <inheritdoc/> | |||
public DateTimeOffset? Reset { get; } | |||
/// <inheritdoc/> | |||
public TimeSpan? ResetAfter { get; } | |||
/// <inheritdoc/> | |||
public string Bucket { get; } | |||
/// <inheritdoc/> | |||
public TimeSpan? Lag { get; } | |||
internal RateLimitInfo(Dictionary<string, string> headers) | |||
/// <inheritdoc/> | |||
public string Endpoint { get; } | |||
internal RateLimitInfo(Dictionary<string, string> headers, string endpoint) | |||
{ | |||
Endpoint = endpoint; | |||
IsGlobal = headers.TryGetValue("X-RateLimit-Global", out string temp) && | |||
bool.TryParse(temp, out var isGlobal) && isGlobal; | |||
Limit = headers.TryGetValue("X-RateLimit-Limit", out temp) && | |||