| @@ -165,5 +165,17 @@ namespace Discord | |||
| /// clock. Your system will still need a stable clock. | |||
| /// </remarks> | |||
| 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; } | |||
| /// <inheritdoc /> | |||
| public TokenType TokenType => ApiClient.AuthTokenType; | |||
| internal bool UseInteractionSnowflakeDate { get; private set; } | |||
| /// <summary> Creates a new REST-only Discord client. </summary> | |||
| internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient client) | |||
| @@ -47,6 +48,8 @@ namespace Discord.Rest | |||
| _restLogger = LogManager.CreateLogger("Rest"); | |||
| _isFirstLogin = config.DisplayInitialLog; | |||
| UseInteractionSnowflakeDate = config.UseInteractionSnowflakeDate; | |||
| ApiClient.RequestQueue.RateLimitTriggered += async (id, info, endpoint) => | |||
| { | |||
| if (info == null) | |||
| @@ -33,8 +33,7 @@ namespace Discord.Rest | |||
| public RestUser User { get; private set; } | |||
| /// <inheritdoc/> | |||
| public DateTimeOffset CreatedAt | |||
| => SnowflakeUtils.FromSnowflake(Id); | |||
| public DateTimeOffset CreatedAt { get; private set; } | |||
| internal abstract bool _hasResponded { get; set; } | |||
| @@ -57,7 +56,9 @@ namespace Discord.Rest | |||
| internal RestInteraction(BaseDiscordClient discord, ulong id) | |||
| : base(discord, id) | |||
| { | |||
| CreatedAt = discord.UseInteractionSnowflakeDate | |||
| ? SnowflakeUtils.FromSnowflake(Id) | |||
| : DateTime.UtcNow; | |||
| } | |||
| internal static async Task<RestInteraction> CreateAsync(DiscordRestClient client, Model model) | |||
| @@ -26,7 +26,7 @@ namespace Discord.WebSocket | |||
| public SocketUserMessage Message { get; private set; } | |||
| 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) | |||
| : base(client, model.Id, channel) | |||
| @@ -130,7 +130,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| if (_hasResponded) | |||
| if (HasResponded) | |||
| { | |||
| throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); | |||
| } | |||
| @@ -140,7 +140,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| _hasResponded = true; | |||
| HasResponded = true; | |||
| } | |||
| } | |||
| @@ -225,7 +225,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| if (_hasResponded) | |||
| if (HasResponded) | |||
| { | |||
| throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); | |||
| } | |||
| @@ -235,7 +235,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| _hasResponded = true; | |||
| HasResponded = true; | |||
| } | |||
| } | |||
| @@ -380,7 +380,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| if (_hasResponded) | |||
| if (HasResponded) | |||
| { | |||
| throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | |||
| } | |||
| @@ -390,7 +390,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| _hasResponded = true; | |||
| HasResponded = true; | |||
| } | |||
| } | |||
| @@ -408,7 +408,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| if (_hasResponded) | |||
| if (HasResponded) | |||
| { | |||
| throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | |||
| } | |||
| @@ -418,7 +418,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| _hasResponded = true; | |||
| HasResponded = true; | |||
| } | |||
| } | |||
| @@ -18,7 +18,7 @@ namespace Discord.WebSocket | |||
| /// </summary> | |||
| public new SocketAutocompleteInteractionData Data { get; } | |||
| internal override bool _hasResponded { get; set; } | |||
| public override bool HasResponded { get; internal set; } | |||
| private object _lock = new object(); | |||
| internal SocketAutocompleteInteraction(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | |||
| @@ -60,7 +60,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| if (_hasResponded) | |||
| if (HasResponded) | |||
| { | |||
| 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); | |||
| lock (_lock) | |||
| { | |||
| _hasResponded = true; | |||
| HasResponded = true; | |||
| } | |||
| } | |||
| @@ -31,7 +31,7 @@ namespace Discord.WebSocket | |||
| /// </summary> | |||
| internal new SocketCommandBaseData Data { get; } | |||
| internal override bool _hasResponded { get; set; } | |||
| public override bool HasResponded { get; internal set; } | |||
| private object _lock = new object(); | |||
| @@ -124,7 +124,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| if (_hasResponded) | |||
| if (HasResponded) | |||
| { | |||
| throw new InvalidOperationException("Cannot respond twice to the same interaction"); | |||
| } | |||
| @@ -134,7 +134,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| _hasResponded = true; | |||
| HasResponded = true; | |||
| } | |||
| } | |||
| @@ -283,7 +283,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| if (_hasResponded) | |||
| if (HasResponded) | |||
| { | |||
| throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); | |||
| } | |||
| @@ -293,7 +293,7 @@ namespace Discord.WebSocket | |||
| lock (_lock) | |||
| { | |||
| _hasResponded = true; | |||
| HasResponded = true; | |||
| } | |||
| } | |||
| } | |||
| @@ -44,10 +44,16 @@ namespace Discord.WebSocket | |||
| public int Version { get; private set; } | |||
| /// <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> | |||
| /// <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) | |||
| { | |||
| Channel = channel; | |||
| CreatedAt = client.UseInteractionSnowflakeDate | |||
| ? SnowflakeUtils.FromSnowflake(Id) | |||
| : DateTime.UtcNow; | |||
| } | |||
| internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | |||