diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 187461b93..879e5613d 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -3916,7 +3916,7 @@ - Gets this guilds slash commands commands + Gets this guilds application commands. The options to be used when sending the request. @@ -3924,6 +3924,18 @@ of application commands found within the guild. + + + Gets an application command within this guild with the specified id. + + The id of the application command to get. + The that determines whether the object should be fetched from cache. + The options to be used when sending the request. + + A ValueTask that represents the asynchronous get operation. The task result contains a + if found, otherwise . + + Holds information for a guild integration feature. @@ -10971,6 +10983,27 @@ A task that represents the asynchronous get operation. The task result contains a read-only collection of connections. + + + Gets a global application command. + + The id of the command. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains the application command if found, otherwise + . + + + + + Gets a collection of all global commands. + + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection of global + application commands. + + Gets a guild. diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index 414b6fe73..a94c1ed33 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -943,7 +943,7 @@ namespace Discord Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null); /// - /// Gets this guilds slash commands commands + /// Gets this guilds application commands. /// /// The options to be used when sending the request. /// @@ -951,5 +951,18 @@ namespace Discord /// of application commands found within the guild. /// Task> GetApplicationCommandsAsync (RequestOptions options = null); + + /// + /// Gets an application command within this guild with the specified id. + /// + /// The id of the application command to get. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A ValueTask that represents the asynchronous get operation. The task result contains a + /// if found, otherwise . + /// + Task GetApplicationCommandAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, + RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/IDiscordClient.cs b/src/Discord.Net.Core/IDiscordClient.cs index d7d6d2856..a728e6096 100644 --- a/src/Discord.Net.Core/IDiscordClient.cs +++ b/src/Discord.Net.Core/IDiscordClient.cs @@ -141,6 +141,27 @@ namespace Discord /// Task> GetConnectionsAsync(RequestOptions options = null); + /// + /// Gets a global application command. + /// + /// The id of the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the application command if found, otherwise + /// . + /// + Task GetGlobalApplicationCommandAsync(ulong id, RequestOptions options = null); + + /// + /// Gets a collection of all global commands. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of global + /// application commands. + /// + Task> GetGlobalApplicationCommandsAsync(RequestOptions options = null); + /// /// Gets a guild. /// diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs index 68589a4f1..c94723281 100644 --- a/src/Discord.Net.Rest/BaseDiscordClient.cs +++ b/src/Discord.Net.Rest/BaseDiscordClient.cs @@ -216,6 +216,14 @@ namespace Discord.Rest Task IDiscordClient.GetWebhookAsync(ulong id, RequestOptions options) => Task.FromResult(null); + /// + Task IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) + => Task.FromResult(null); + + /// + Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) + => Task.FromResult>(ImmutableArray.Create()); + /// Task IDiscordClient.StartAsync() => Task.Delay(0); diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs index 0161483c9..19c3b1325 100644 --- a/src/Discord.Net.Rest/ClientHelper.cs +++ b/src/Discord.Net.Rest/ClientHelper.cs @@ -194,7 +194,8 @@ namespace Discord.Rest }; } - public static async Task> GetGlobalApplicationCommands(BaseDiscordClient client, RequestOptions options) + public static async Task> GetGlobalApplicationCommands(BaseDiscordClient client, + RequestOptions options = null) { var response = await client.ApiClient.GetGlobalApplicationCommandsAsync(options).ConfigureAwait(false); @@ -203,8 +204,16 @@ namespace Discord.Rest return response.Select(x => RestGlobalCommand.Create(client, x)).ToArray(); } + public static async Task GetGlobalApplicationCommand(BaseDiscordClient client, ulong id, + RequestOptions options = null) + { + var model = await client.ApiClient.GetGlobalApplicationCommandAsync(id, options); + + return model != null ? RestGlobalCommand.Create(client, model) : null; + } - public static async Task> GetGuildApplicationCommands(BaseDiscordClient client, ulong guildId, RequestOptions options) + public static async Task> GetGuildApplicationCommands(BaseDiscordClient client, ulong guildId, + RequestOptions options = null) { var response = await client.ApiClient.GetGuildApplicationCommandsAsync(guildId, options).ConfigureAwait(false); @@ -213,6 +222,13 @@ namespace Discord.Rest return response.Select(x => RestGuildCommand.Create(client, x, guildId)).ToImmutableArray(); } + public static async Task GetGuildApplicationCommand(BaseDiscordClient client, ulong id, ulong guildId, + RequestOptions options = null) + { + var model = await client.ApiClient.GetGuildApplicationCommandAsync(guildId, id, options); + + return model != null ? RestGuildCommand.Create(client, model, guildId) : null; + } public static Task AddRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index 0378df092..2167ad1c5 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -226,6 +226,12 @@ + + + + + + @@ -299,6 +305,12 @@ + + + + + + Represents a configuration class for . @@ -3503,6 +3515,17 @@ of application commands found within the guild. + + + Gets an application command within this guild with the specified id. + + The id of the application command to get. + The options to be used when sending the request. + + A ValueTask that represents the asynchronous get operation. The task result contains a + if found, otherwise . + + Returns the name of the guild. diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 8bf7f6e43..f73799943 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -1063,6 +1063,18 @@ namespace Discord.API return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/commands", new BucketIds(), options: options).ConfigureAwait(false); } + public async Task GetGlobalApplicationCommandAsync(ulong id, RequestOptions options = null) + { + Preconditions.NotEqual(id, 0, nameof(id)); + + options = RequestOptions.CreateOrClone(options); + + try + { + return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/commands/{id}", new BucketIds(), options: options).ConfigureAwait(false); + } + catch(HttpException x) when (x.HttpCode == HttpStatusCode.NotFound) { return null; } + } public async Task CreateGlobalApplicationCommandAsync(CreateApplicationCommandParams command, RequestOptions options = null) { @@ -1074,7 +1086,6 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); - return await TrySendApplicationCommand(SendJsonAsync("POST", () => $"applications/{this.CurrentUserId}/commands", command, new BucketIds(), options: options)).ConfigureAwait(false); } public async Task ModifyGlobalApplicationCommandAsync(ModifyApplicationCommandParams command, ulong commandId, RequestOptions options = null) @@ -1158,7 +1169,11 @@ namespace Discord.API var bucket = new BucketIds(guildId: guildId); - return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options); + try + { + return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options); + } + catch(HttpException x) when (x.HttpCode == HttpStatusCode.NotFound) { return null; } } public async Task CreateGuildApplicationCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null) @@ -1195,58 +1210,6 @@ namespace Discord.API return await TrySendApplicationCommand(SendJsonAsync("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false); } - public async Task CreateGuildApplicationUserCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null) - { - options = RequestOptions.CreateOrClone(options); - - var bucket = new BucketIds(guildId: guildId); - - return await TrySendApplicationCommand(SendJsonAsync("POST", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", command, bucket, options: options)).ConfigureAwait(false); - } - - public async Task ModifyGuildApplicationUserCommandAsync(ModifyApplicationCommandParams command, ulong guildId, ulong commandId, RequestOptions options = null) - { - options = RequestOptions.CreateOrClone(options); - - var bucket = new BucketIds(guildId: guildId); - - return await TrySendApplicationCommand(SendJsonAsync("PATCH", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", command, bucket, options: options)).ConfigureAwait(false); - } - public async Task BulkOverwriteGuildApplicationUserCommands(ulong guildId, CreateApplicationCommandParams[] commands, RequestOptions options = null) - { - options = RequestOptions.CreateOrClone(options); - - var bucket = new BucketIds(guildId: guildId); - - return await TrySendApplicationCommand(SendJsonAsync("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false); - } - - public async Task CreateGuildApplicationMessageCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null) - { - options = RequestOptions.CreateOrClone(options); - - var bucket = new BucketIds(guildId: guildId); - - return await TrySendApplicationCommand(SendJsonAsync("POST", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", command, bucket, options: options)).ConfigureAwait(false); - } - public async Task ModifyGuildApplicationMessageCommandAsync(ModifyApplicationCommandParams command, ulong guildId, ulong commandId, RequestOptions options = null) - { - options = RequestOptions.CreateOrClone(options); - - var bucket = new BucketIds(guildId: guildId); - - return await TrySendApplicationCommand(SendJsonAsync("PATCH", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", command, bucket, options: options)).ConfigureAwait(false); - } - - public async Task BulkOverwriteGuildApplicationMessageCommands(ulong guildId, CreateApplicationCommandParams[] commands, RequestOptions options = null) - { - options = RequestOptions.CreateOrClone(options); - - var bucket = new BucketIds(guildId: guildId); - - return await TrySendApplicationCommand(SendJsonAsync("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false); - } - //Interaction Responses public async Task CreateInteractionResponse(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null) { diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs index 32dbaf40e..feef4c12a 100644 --- a/src/Discord.Net.Rest/DiscordRestClient.cs +++ b/src/Discord.Net.Rest/DiscordRestClient.cs @@ -226,5 +226,12 @@ namespace Discord.Rest /// async Task IDiscordClient.GetWebhookAsync(ulong id, RequestOptions options) => await GetWebhookAsync(id, options).ConfigureAwait(false); + + /// + async Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) + => await GetGlobalApplicationCommands(options).ConfigureAwait(false); + /// + async Task IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) + => await ClientHelper.GetGlobalApplicationCommand(this, id, options).ConfigureAwait(false); } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 126a211c8..bf4365a5f 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -878,8 +878,19 @@ namespace Discord.Rest /// A task that represents the asynchronous get operation. The task result contains a read-only collection /// of application commands found within the guild. /// - public async Task> GetApplicationCommandsAsync (RequestOptions options = null) + public async Task> GetApplicationCommandsAsync (RequestOptions options = null) => await ClientHelper.GetGuildApplicationCommands(Discord, Id, options).ConfigureAwait(false); + /// + /// Gets an application command within this guild with the specified id. + /// + /// The id of the application command to get. + /// The options to be used when sending the request. + /// + /// A ValueTask that represents the asynchronous get operation. The task result contains a + /// if found, otherwise . + /// + public async Task GetApplicationCommandAsync(ulong id, RequestOptions options = null) + => await ClientHelper.GetGuildApplicationCommand(Discord, id, this.Id, options); /// /// Returns the name of the guild. @@ -1169,5 +1180,14 @@ namespace Discord.Rest /// async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options) => await GetApplicationCommandsAsync(options).ConfigureAwait(false); + async Task IGuild.GetApplicationCommandAsync(ulong id, CacheMode mode, RequestOptions options) + { + if (mode == CacheMode.AllowDownload) + { + return await GetApplicationCommandAsync(id, options); + } + else + return null; + } } } diff --git a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs index fbbce4f4b..adf6226e2 100644 --- a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs +++ b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs @@ -44,12 +44,20 @@ namespace Discord.Rest } // Global commands - public static async Task CreateGlobalCommand(BaseDiscordClient client, - Action func, RequestOptions options) where TArg : ApplicationCommandProperties + public static async Task GetGlobalCommandAsync(BaseDiscordClient client, ulong id, + RequestOptions options = null) + { + var model = await client.ApiClient.GetGlobalApplicationCommandAsync(id, options).ConfigureAwait(false); + + + return RestGlobalCommand.Create(client, model); + } + public static Task CreateGlobalCommand(BaseDiscordClient client, + Action func, RequestOptions options = null) where TArg : ApplicationCommandProperties { var args = Activator.CreateInstance(typeof(TArg)); func((TArg)args); - return await CreateGlobalCommand(client, (TArg)args, options); + return CreateGlobalCommand(client, (TArg)args, options); } public static async Task CreateGlobalCommand(BaseDiscordClient client, ApplicationCommandProperties arg, RequestOptions options = null) @@ -116,7 +124,7 @@ namespace Discord.Rest models.Add(model); } - var apiModels = await client.ApiClient.BulkOverwriteGlobalApplicationCommands(models.ToArray(), options); + var apiModels = await client.ApiClient.BulkOverwriteGlobalApplicationCommands(models.ToArray(), options).ConfigureAwait(false); return apiModels.Select(x => RestGlobalCommand.Create(client, x)).ToArray(); } @@ -156,7 +164,7 @@ namespace Discord.Rest models.Add(model); } - var apiModels = await client.ApiClient.BulkOverwriteGuildApplicationCommands(guildId, models.ToArray(), options); + var apiModels = await client.ApiClient.BulkOverwriteGuildApplicationCommands(guildId, models.ToArray(), options).ConfigureAwait(false); return apiModels.Select(x => RestGuildCommand.Create(client, x, guildId)).ToArray(); } @@ -221,12 +229,12 @@ namespace Discord.Rest } // Guild Commands - public static async Task CreateGuildCommand(BaseDiscordClient client, ulong guildId, + public static Task CreateGuildCommand(BaseDiscordClient client, ulong guildId, Action func, RequestOptions options) where TArg : ApplicationCommandProperties { var args = Activator.CreateInstance(typeof(TArg)); func((TArg)args); - return await CreateGuildCommand(client, guildId, (TArg)args, options); + return CreateGuildCommand(client, guildId, (TArg)args, options); } public static async Task CreateGuildCommand(BaseDiscordClient client, ulong guildId, diff --git a/src/Discord.Net.WebSocket/ClientState.cs b/src/Discord.Net.WebSocket/ClientState.cs index f2e370d02..653eec4c8 100644 --- a/src/Discord.Net.WebSocket/ClientState.cs +++ b/src/Discord.Net.WebSocket/ClientState.cs @@ -16,12 +16,14 @@ namespace Discord.WebSocket private readonly ConcurrentDictionary _guilds; private readonly ConcurrentDictionary _users; private readonly ConcurrentHashSet _groupChannels; + private readonly ConcurrentDictionary _commands; internal IReadOnlyCollection Channels => _channels.ToReadOnlyCollection(); internal IReadOnlyCollection DMChannels => _dmChannels.ToReadOnlyCollection(); internal IReadOnlyCollection GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels); internal IReadOnlyCollection Guilds => _guilds.ToReadOnlyCollection(); internal IReadOnlyCollection Users => _users.ToReadOnlyCollection(); + internal IReadOnlyCollection Commands => _commands.ToReadOnlyCollection(); internal IReadOnlyCollection PrivateChannels => _dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat( @@ -139,5 +141,22 @@ namespace Discord.WebSocket foreach (var guild in _guilds.Values) guild.PurgeGuildUserCache(); } + + internal SocketApplicationCommand GetCommand(ulong id) + { + if (_commands.TryGetValue(id, out SocketApplicationCommand command)) + return command; + return null; + } + internal void AddCommand(SocketApplicationCommand command) + { + _commands[command.Id] = command; + } + internal SocketApplicationCommand RemoveCommand(ulong id) + { + if (_commands.TryRemove(id, out SocketApplicationCommand command)) + return command; + return null; + } } } diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index b2a823741..faacf90ab 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -1078,6 +1078,27 @@ + + + Gets a global application command. + + The id of the command. + The options to be used when sending the request. + + A ValueTask that represents the asynchronous get operation. The task result contains the application command if found, otherwise + . + + + + + Gets a collection of all global commands. + + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection of global + application commands. + + Clears cached users from the client. @@ -1166,6 +1187,12 @@ + + + + + + diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 0da71faf2..53d712dbf 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -343,6 +343,54 @@ namespace Discord.WebSocket /// public override SocketUser GetUser(string username, string discriminator) => State.Users.FirstOrDefault(x => x.Discriminator == discriminator && x.Username == username); + + /// + /// Gets a global application command. + /// + /// The id of the command. + /// The options to be used when sending the request. + /// + /// A ValueTask that represents the asynchronous get operation. The task result contains the application command if found, otherwise + /// . + /// + public async ValueTask GetGlobalApplicationCommandAsync(ulong id, RequestOptions options = null) + { + var command = State.GetCommand(id); + + if (command != null) + return command; + + var model = await ApiClient.GetGlobalApplicationCommandAsync(id, options); + + if (model == null) + return null; + + command = SocketApplicationCommand.Create(this, model); + + State.AddCommand(command); + + return command; + } + /// + /// Gets a collection of all global commands. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of global + /// application commands. + /// + public async Task> GetGlobalApplicationCommandsAsync(RequestOptions options = null) + { + var commands = (await ApiClient.GetGlobalApplicationCommandsAsync(options)).Select(x => SocketApplicationCommand.Create(this, x)); + + foreach(var command in commands) + { + State.AddCommand(command); + } + + return commands.ToImmutableArray(); + } + /// /// Clears cached users from the client. /// @@ -1891,8 +1939,6 @@ namespace Discord.WebSocket { await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); - // 0x546861742062696720656e6469616e20656e636f64696e67206d616b6573206d79316d687a20636c6f636b207469636b - var data = (payload as JToken).ToObject(_serializer); SocketChannel channel = null; @@ -1958,6 +2004,8 @@ namespace Discord.WebSocket var applicationCommand = SocketApplicationCommand.Create(this, data); + State.AddCommand(applicationCommand); + await TimedInvokeAsync(_applicationCommandCreated, nameof(ApplicationCommandCreated), applicationCommand).ConfigureAwait(false); } break; @@ -1979,6 +2027,8 @@ namespace Discord.WebSocket var applicationCommand = SocketApplicationCommand.Create(this, data); + State.AddCommand(applicationCommand); + await TimedInvokeAsync(_applicationCommandUpdated, nameof(ApplicationCommandUpdated), applicationCommand).ConfigureAwait(false); } break; @@ -2000,6 +2050,8 @@ namespace Discord.WebSocket var applicationCommand = SocketApplicationCommand.Create(this, data); + State.RemoveCommand(applicationCommand.Id); + await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false); } break; @@ -2611,6 +2663,13 @@ namespace Discord.WebSocket async Task IDiscordClient.GetVoiceRegionAsync(string id, RequestOptions options) => await GetVoiceRegionAsync(id, options).ConfigureAwait(false); + /// + async Task IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) + => await GetGlobalApplicationCommandAsync(id, options); + /// + async Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) + => await GetGlobalApplicationCommandsAsync(options); + /// async Task IDiscordClient.StartAsync() => await StartAsync().ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 5c385fe01..3b92e6a22 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -785,13 +785,13 @@ namespace Discord.WebSocket //Interactions /// - /// Deletes all slash commands in the current guild. + /// Deletes all application commands in the current guild. /// /// The options to be used when sending the request. /// /// A task that represents the asynchronous delete operation. /// - public Task DeleteSlashCommandsAsync(RequestOptions options = null) + public Task DeleteApplicationCommandsAsync(RequestOptions options = null) => InteractionHelper.DeleteAllGuildCommandsAsync(Discord, this.Id, options); /// @@ -802,20 +802,39 @@ namespace Discord.WebSocket /// A task that represents the asynchronous get operation. The task result contains a read-only collection of /// slash commands created by the current user. /// - public Task> GetSlashCommandsAsync(RequestOptions options = null) - => GuildHelper.GetSlashCommandsAsync(this, Discord, options); + public async Task> GetApplicationCommandsAsync(RequestOptions options = null) + { + var commands = (await Discord.ApiClient.GetGuildApplicationCommandsAsync(this.Id, options)).Select(x => SocketApplicationCommand.Create(Discord, x)); - /// - /// Gets a slash command in the current guild. - /// - /// The unique identifier of the slash command. - /// The options to be used when sending the request. - /// - /// A task that represents the asynchronous get operation. The task result contains a - /// slash command created by the current user. - /// - public Task GetSlashCommandAsync(ulong id, RequestOptions options = null) - => GuildHelper.GetSlashCommandAsync(this, id, Discord, options); + foreach (var command in commands) + { + Discord.State.AddCommand(command); + } + + return commands.ToImmutableArray(); + } + + public async ValueTask GetApplicationCommandAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) + { + var command = Discord.State.GetCommand(id); + + if (command != null) + return command; + + if (mode == CacheMode.CacheOnly) + return null; + + var model = await Discord.ApiClient.GetGlobalApplicationCommandAsync(id, options); + + if (model == null) + return null; + + command = SocketApplicationCommand.Create(Discord, model); + + Discord.State.AddCommand(command); + + return command; + } //Invites /// @@ -1079,18 +1098,6 @@ namespace Discord.WebSocket public Task> GetWebhooksAsync(RequestOptions options = null) => GuildHelper.GetWebhooksAsync(this, Discord, options); - //Interactions - /// - /// Gets this guilds slash commands commands - /// - /// The options to be used when sending the request. - /// - /// A task that represents the asynchronous get operation. The task result contains a read-only collection - /// of application commands found within the guild. - /// - public async Task> GetApplicationCommandsAsync(RequestOptions options = null) - => await Discord.Rest.GetGuildApplicationCommands(this.Id, options); - //Emotes /// public Task> GetEmotesAsync(RequestOptions options = null) @@ -1481,6 +1488,8 @@ namespace Discord.WebSocket /// async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options) => await GetApplicationCommandsAsync(options).ConfigureAwait(false); + async Task IGuild.GetApplicationCommandAsync(ulong id, CacheMode mode, RequestOptions options) + => await GetApplicationCommandAsync(id, mode, options); void IDisposable.Dispose() { diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandCache.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandCache.cs deleted file mode 100644 index 7dd30151d..000000000 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandCache.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Discord.WebSocket.Entities.Interaction -{ - internal class SlashCommandCache - { - private readonly ConcurrentDictionary _slashCommands; - private readonly ConcurrentQueue _orderedSlashCommands; - private readonly int _size; - - public IReadOnlyCollection Messages => _slashCommands.ToReadOnlyCollection(); - - public SlashCommandCache(DiscordSocketClient client) - { - _size = 256; - _slashCommands = new ConcurrentDictionary(); - - } - - public void Add(SocketSlashCommand slashCommand) - { - if (_slashCommands.TryAdd(slashCommand.Id, slashCommand)) - { - _orderedSlashCommands.Enqueue(slashCommand.Id); - - while (_orderedSlashCommands.Count > _size && _orderedSlashCommands.TryDequeue(out ulong msgId)) - _slashCommands.TryRemove(msgId, out _); - } - } - - public SocketSlashCommand Remove(ulong id) - { - _slashCommands.TryRemove(id, out var slashCommand); - return slashCommand; - } - - public SocketSlashCommand Get(ulong id) - { - _slashCommands.TryGetValue(id, out var slashCommands); - return slashCommands; - } - } -} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs index 8d4a4d485..77a43a1e3 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs @@ -5,7 +5,8 @@ using System.Collections.Immutable; using System.Linq; using System.Text; using System.Threading.Tasks; -using Model = Discord.API.Gateway.ApplicationCommandCreatedUpdatedEvent; +using GatewayModel = Discord.API.Gateway.ApplicationCommandCreatedUpdatedEvent; +using Model = Discord.API.ApplicationCommand; namespace Discord.WebSocket { @@ -60,14 +61,21 @@ namespace Discord.WebSocket { this.GuildId = guildId; } - internal static SocketApplicationCommand Create(DiscordSocketClient client, Model model) + internal static SocketApplicationCommand Create(DiscordSocketClient client, GatewayModel model) { var entity = new SocketApplicationCommand(client, model.Id, model.GuildId.ToNullable()); entity.Update(model); return entity; } - internal void Update(API.ApplicationCommand model) + internal static SocketApplicationCommand Create(DiscordSocketClient client, Model model, ulong? guildId = null) + { + var entity = new SocketApplicationCommand(client, model.Id, guildId); + entity.Update(model); + return entity; + } + + internal void Update(Model model) { this.ApplicationId = model.ApplicationId; this.Description = model.Description; @@ -102,7 +110,7 @@ namespace Discord.WebSocket throw new InvalidOperationException($"Cannot modify this application command with the parameter type {nameof(TArg)}"); } - API.ApplicationCommand command = null; + Model command = null; if (this.IsGlobalCommand) {