@@ -165,5 +165,17 @@ namespace Discord | |||||
/// clock. Your system will still need a stable clock. | /// clock. Your system will still need a stable clock. | ||||
/// </remarks> | /// </remarks> | ||||
public bool UseSystemClock { get; set; } = true; | public bool UseSystemClock { get; set; } = true; | ||||
/// <summary> | |||||
/// Gets or sets whether or not the internal experation check uses the system date | |||||
/// + snowflake date to check if an interaction can be responded to. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// If set to <see langword="false"/> then the CreatedAt property in an interaction | |||||
/// will be set to when it was received instead of the snowflakes date. | |||||
/// <br/> | |||||
/// <b>This will still require a stable clock on your system.</b> | |||||
/// </remarks> | |||||
public bool UseInteractionSnowflakeDate { get; set; } = true; | |||||
} | } | ||||
} | } |
@@ -35,6 +35,7 @@ namespace Discord.Rest | |||||
public ISelfUser CurrentUser { get; protected set; } | public ISelfUser CurrentUser { get; protected set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public TokenType TokenType => ApiClient.AuthTokenType; | public TokenType TokenType => ApiClient.AuthTokenType; | ||||
internal bool UseInteractionSnowflakeDate { get; private set; } | |||||
/// <summary> Creates a new REST-only Discord client. </summary> | /// <summary> Creates a new REST-only Discord client. </summary> | ||||
internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient client) | internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient client) | ||||
@@ -47,6 +48,8 @@ namespace Discord.Rest | |||||
_restLogger = LogManager.CreateLogger("Rest"); | _restLogger = LogManager.CreateLogger("Rest"); | ||||
_isFirstLogin = config.DisplayInitialLog; | _isFirstLogin = config.DisplayInitialLog; | ||||
UseInteractionSnowflakeDate = config.UseInteractionSnowflakeDate; | |||||
ApiClient.RequestQueue.RateLimitTriggered += async (id, info, endpoint) => | ApiClient.RequestQueue.RateLimitTriggered += async (id, info, endpoint) => | ||||
{ | { | ||||
if (info == null) | if (info == null) | ||||
@@ -33,8 +33,7 @@ namespace Discord.Rest | |||||
public RestUser User { get; private set; } | public RestUser User { get; private set; } | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public DateTimeOffset CreatedAt | |||||
=> SnowflakeUtils.FromSnowflake(Id); | |||||
public DateTimeOffset CreatedAt { get; private set; } | |||||
internal abstract bool _hasResponded { get; set; } | internal abstract bool _hasResponded { get; set; } | ||||
@@ -57,7 +56,9 @@ namespace Discord.Rest | |||||
internal RestInteraction(BaseDiscordClient discord, ulong id) | internal RestInteraction(BaseDiscordClient discord, ulong id) | ||||
: base(discord, id) | : base(discord, id) | ||||
{ | { | ||||
CreatedAt = discord.UseInteractionSnowflakeDate | |||||
? SnowflakeUtils.FromSnowflake(Id) | |||||
: DateTime.UtcNow; | |||||
} | } | ||||
internal static async Task<RestInteraction> CreateAsync(DiscordRestClient client, Model model) | internal static async Task<RestInteraction> CreateAsync(DiscordRestClient client, Model model) | ||||
@@ -26,7 +26,7 @@ namespace Discord.WebSocket | |||||
public SocketUserMessage Message { get; private set; } | public SocketUserMessage Message { get; private set; } | ||||
private object _lock = new object(); | private object _lock = new object(); | ||||
internal override bool _hasResponded { get; set; } = false; | |||||
public override bool HasResponded { get; internal set; } = false; | |||||
internal SocketMessageComponent(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | internal SocketMessageComponent(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | ||||
: base(client, model.Id, channel) | : base(client, model.Id, channel) | ||||
@@ -130,7 +130,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
if (_hasResponded) | |||||
if (HasResponded) | |||||
{ | { | ||||
throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); | throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); | ||||
} | } | ||||
@@ -140,7 +140,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
_hasResponded = true; | |||||
HasResponded = true; | |||||
} | } | ||||
} | } | ||||
@@ -225,7 +225,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
if (_hasResponded) | |||||
if (HasResponded) | |||||
{ | { | ||||
throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); | throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); | ||||
} | } | ||||
@@ -235,7 +235,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
_hasResponded = true; | |||||
HasResponded = true; | |||||
} | } | ||||
} | } | ||||
@@ -380,7 +380,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
if (_hasResponded) | |||||
if (HasResponded) | |||||
{ | { | ||||
throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | ||||
} | } | ||||
@@ -390,7 +390,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
_hasResponded = true; | |||||
HasResponded = true; | |||||
} | } | ||||
} | } | ||||
@@ -408,7 +408,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
if (_hasResponded) | |||||
if (HasResponded) | |||||
{ | { | ||||
throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | ||||
} | } | ||||
@@ -418,7 +418,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
_hasResponded = true; | |||||
HasResponded = true; | |||||
} | } | ||||
} | } | ||||
@@ -18,7 +18,7 @@ namespace Discord.WebSocket | |||||
/// </summary> | /// </summary> | ||||
public new SocketAutocompleteInteractionData Data { get; } | public new SocketAutocompleteInteractionData Data { get; } | ||||
internal override bool _hasResponded { get; set; } | |||||
public override bool HasResponded { get; internal set; } | |||||
private object _lock = new object(); | private object _lock = new object(); | ||||
internal SocketAutocompleteInteraction(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | internal SocketAutocompleteInteraction(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | ||||
@@ -60,7 +60,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
if (_hasResponded) | |||||
if (HasResponded) | |||||
{ | { | ||||
throw new InvalidOperationException("Cannot respond twice to the same interaction"); | throw new InvalidOperationException("Cannot respond twice to the same interaction"); | ||||
} | } | ||||
@@ -69,7 +69,7 @@ namespace Discord.WebSocket | |||||
await InteractionHelper.SendAutocompleteResultAsync(Discord, result, Id, Token, options).ConfigureAwait(false); | await InteractionHelper.SendAutocompleteResultAsync(Discord, result, Id, Token, options).ConfigureAwait(false); | ||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
_hasResponded = true; | |||||
HasResponded = true; | |||||
} | } | ||||
} | } | ||||
@@ -31,7 +31,7 @@ namespace Discord.WebSocket | |||||
/// </summary> | /// </summary> | ||||
internal new SocketCommandBaseData Data { get; } | internal new SocketCommandBaseData Data { get; } | ||||
internal override bool _hasResponded { get; set; } | |||||
public override bool HasResponded { get; internal set; } | |||||
private object _lock = new object(); | private object _lock = new object(); | ||||
@@ -124,7 +124,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
if (_hasResponded) | |||||
if (HasResponded) | |||||
{ | { | ||||
throw new InvalidOperationException("Cannot respond twice to the same interaction"); | throw new InvalidOperationException("Cannot respond twice to the same interaction"); | ||||
} | } | ||||
@@ -134,7 +134,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
_hasResponded = true; | |||||
HasResponded = true; | |||||
} | } | ||||
} | } | ||||
@@ -283,7 +283,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
if (_hasResponded) | |||||
if (HasResponded) | |||||
{ | { | ||||
throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | ||||
} | } | ||||
@@ -293,7 +293,7 @@ namespace Discord.WebSocket | |||||
lock (_lock) | lock (_lock) | ||||
{ | { | ||||
_hasResponded = true; | |||||
HasResponded = true; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -44,10 +44,16 @@ namespace Discord.WebSocket | |||||
public int Version { get; private set; } | public int Version { get; private set; } | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public DateTimeOffset CreatedAt | |||||
=> SnowflakeUtils.FromSnowflake(Id); | |||||
public DateTimeOffset CreatedAt { get; private set; } | |||||
internal abstract bool _hasResponded { get; set; } | |||||
/// <summary> | |||||
/// Gets whether or not this interaction has been responded to. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This property is locally set -- if you're running multiple bots | |||||
/// off the same token then this property won't be in sync with them. | |||||
/// </remarks> | |||||
public abstract bool HasResponded { get; internal set; } | |||||
/// <summary> | /// <summary> | ||||
/// <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/>. | /// <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/>. | ||||
@@ -59,6 +65,10 @@ namespace Discord.WebSocket | |||||
: base(client, id) | : base(client, id) | ||||
{ | { | ||||
Channel = channel; | Channel = channel; | ||||
CreatedAt = client.UseInteractionSnowflakeDate | |||||
? SnowflakeUtils.FromSnowflake(Id) | |||||
: DateTime.UtcNow; | |||||
} | } | ||||
internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | ||||