diff --git a/Cocotte/Modules/PingModule.cs b/Cocotte/Modules/PingModule.cs index 7cdac92..bcaf9f6 100644 --- a/Cocotte/Modules/PingModule.cs +++ b/Cocotte/Modules/PingModule.cs @@ -1,19 +1,176 @@ -using Discord.Interactions; +#if DEBUG + +using Cocotte.Services; +using Discord; +using Discord.Interactions; namespace Cocotte.Modules; +/// +/// Module containing different test and debug commands +/// +[RequireOwner] public class PingModule : InteractionModuleBase { private readonly ILogger _logger; + private readonly SharedCounter _sharedCounter; + private readonly TransientCounter _transientCounter; + private static readonly SemaphoreSlim CounterWait = new(0); - public PingModule(ILogger logger) + public PingModule(ILogger logger, SharedCounter sharedCounter, TransientCounter transientCounter) { _logger = logger; + _sharedCounter = sharedCounter; + _transientCounter = transientCounter; } - [SlashCommand("ping", "Check if Coco is alive")] + [SlashCommand("ping", "Check if Coco is alive and get latency")] public async Task Ping() { - await RespondAsync($":ping_pong: It took me {Context.Client.Latency}ms to respond to you!", ephemeral: true); + _logger.LogTrace("[Ping/ping] Received ping command"); + + await RespondAsync($":ping_pong: It took me {Context.Client.Latency}ms to respond to you!"); } -} \ No newline at end of file + + [SlashCommand("echo", "Repeat the input")] + public async Task Echo(string echo, [Summary(description: "mention the user")] bool mention = false) + { + _logger.LogTrace("[Ping/echo] Received ping command with arg: {{ echo:'{Echo}', mention:{Mention} }}", echo, mention); + + await RespondAsync($"{echo} {(mention ? Context.User.Mention : string.Empty)}"); + } + + // This command will greet target user in the channel this was executed in. + [UserCommand("Greet")] + public async Task GreetUserAsync(IUser user) + { + await RespondAsync($":wave: {Context.User.Username} said hi to you, <@{user.Id}>!"); + } + + // Pins a message in the channel it is in. + [MessageCommand("Pin")] + public async Task PinMessageAsync(IMessage message) + { + // make a safety cast to check if the message is ISystem- or IUserMessage + if (message is not IUserMessage userMessage) + await RespondAsync(":x: You cant pin system messages!"); + + // if the pins in this channel are equal to or above 50, no more messages can be pinned. + else if ((await Context.Channel.GetPinnedMessagesAsync()).Count >= 50) + await RespondAsync(":x: You cant pin any more messages, the max has already been reached in this channel!"); + + else + { + await userMessage.PinAsync(); + await RespondAsync(":white_check_mark: Successfully pinned message!"); + } + } + + [SlashCommand("test-button", "Test buttons components")] + public async Task TestButton() + { + var component = new ComponentBuilder() + .WithButton("Button1", $"button:1:{Context.User.Username}") + .WithButton("Button2", $"button:2:{Context.User.Username}") + .AddRow(new ActionRowBuilder() + .WithButton("Button3", $"button:3:{Context.User.Username}")); + + await RespondAsync(components: component.Build()); + } + + [ComponentInteraction("button:*:*")] + public async Task TestButtonClick(int buttonId, string userName) + { + await RespondAsync($"{userName} clicked on button: {buttonId}"); + } + + [SlashCommand("counter-shared", "Spawn a shared counter")] + public async Task CounterShared() + { + var component = new ComponentBuilder() + .WithButton("Increment", "increment_shared"); + + await RespondAsync($"Counter: {_sharedCounter.Count}", components: component.Build()); + } + + [ComponentInteraction("increment_shared")] + public async Task SharedCounterIncrement() + { + _logger.LogTrace("Received increment on shared counter"); + _sharedCounter.Count++; + + try + { + await (Context.Interaction as IComponentInteraction)!.UpdateAsync(msg => + { + msg.Content = $"Counter: {_sharedCounter.Count}"; + }); + } + catch (Exception e) + { + _logger.LogError(e, "An error occured while updating original message:"); + } + await RespondAsync(); + } + + [SlashCommand("counter-transient", "Spawn a transient counter")] + public async Task CounterTransient() + { + var component = new ComponentBuilder() + .WithButton("Increment", "increment_transient"); + + await RespondAsync($"Counter: {_transientCounter.Count}", components: component.Build()); + } + + [ComponentInteraction("increment_transient")] + public async Task TransientCounterIncrement() + { + _logger.LogTrace("Received increment on transient counter"); + _transientCounter.Count++; + + try + { + await (Context.Interaction as IComponentInteraction)!.UpdateAsync(msg => + { + msg.Content = $"Counter: {_transientCounter.Count}"; + }); + } + catch (Exception e) + { + _logger.LogError(e, "An error occured while updating original message:"); + } + await RespondAsync(); + } + + [SlashCommand("counter-transient-wait", "Spawn a transient counter using wait")] + public async Task CounterTransientWait() + { + var component = new ComponentBuilder() + .WithButton("Increment", "increment_transient_wait"); + + await RespondAsync($"Counter: {_transientCounter.Count}", components: component.Build()); + var response = await GetOriginalResponseAsync(); + + while (true) + { + // Wait for the button to be clicked + _logger.LogTrace("Waiting for semaphore release"); + await CounterWait.WaitAsync(); + + _logger.LogTrace("Received increment on transient wait counter"); + _transientCounter.Count++; + + await ModifyOriginalResponseAsync(m => m.Content = $"Counter: {_transientCounter.Count}"); + } + } + + [ComponentInteraction("increment_transient_wait")] + public async Task WaitCounterIncrement() + { + CounterWait.Release(); + + await RespondAsync(); + } +} + +#endif \ No newline at end of file diff --git a/Cocotte/Program.cs b/Cocotte/Program.cs index 3d8ee51..acef6d9 100644 --- a/Cocotte/Program.cs +++ b/Cocotte/Program.cs @@ -34,6 +34,7 @@ IHost host = Host.CreateDefaultBuilder(args) // Custom services.AddSingleton(); + services.AddTransient(); }) .Build(); diff --git a/Cocotte/Properties/launchSettings.json b/Cocotte/Properties/launchSettings.json index e499d8b..0b60e26 100644 --- a/Cocotte/Properties/launchSettings.json +++ b/Cocotte/Properties/launchSettings.json @@ -1,6 +1,6 @@ { "profiles": { - "Cocotter": { + "Cocotte": { "commandName": "Project", "dotnetRunMessages": true, "environmentVariables": { diff --git a/Cocotte/Services/CocotteService.cs b/Cocotte/Services/CocotteService.cs index 49271fd..75672de 100644 --- a/Cocotte/Services/CocotteService.cs +++ b/Cocotte/Services/CocotteService.cs @@ -1,6 +1,5 @@ using System.Reflection; using Cocotte.Options; -using Cocotte.Utils; using Discord; using Discord.Interactions; using Discord.WebSocket; @@ -72,7 +71,7 @@ public class CocotteService : BackgroundService return; } - await _interactionService.RegisterCommandsToGuildAsync(_options.DevGuildId.Value, true); + await _interactionService.RegisterCommandsToGuildAsync(_options.DevGuildId.Value); } else { @@ -87,7 +86,7 @@ public class CocotteService : BackgroundService private async Task HandleInteraction(SocketInteraction interaction) { - _logger.LogTrace("[Interaction/Trace] Received interaction: by {user} in #{channel} of type {type}", interaction.User, interaction.Channel, interaction.Type); + _logger.LogTrace("[Interaction/Trace] Received interaction: by {User} in #{Channel} of type {Type}", interaction.User, interaction.Channel, interaction.Type); try { @@ -99,14 +98,7 @@ public class CocotteService : BackgroundService if (!result.IsSuccess) { - _logger.LogDebug("[Interaction/Trace] Error while executing interaction: {interaction} in {channel}", interaction.Token, interaction.Channel); - - switch (result.Error) - { - case InteractionCommandError.UnmetPrecondition: - // implement - break; - } + _logger.LogDebug("[Interaction/Trace] Error while executing interaction: {Interaction} in {Channel} because {Error}:{Reason}", interaction.Token, interaction.Channel, result.Error, result.ErrorReason); } } catch diff --git a/Cocotte/Services/TransientCounter.cs b/Cocotte/Services/TransientCounter.cs new file mode 100644 index 0000000..edb477f --- /dev/null +++ b/Cocotte/Services/TransientCounter.cs @@ -0,0 +1,6 @@ +namespace Cocotte.Services; + +public class TransientCounter +{ + public int Count { get; set; } = 0; +} \ No newline at end of file diff --git a/Cocotte/appsettings.Development.json b/Cocotte/appsettings.Development.json index b2dcdb6..b4be21e 100644 --- a/Cocotte/appsettings.Development.json +++ b/Cocotte/appsettings.Development.json @@ -2,7 +2,8 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.Hosting.Lifetime": "Information" + "Microsoft.Hosting.Lifetime": "Information", + "Cocotte": "Trace" } } }