using Discord.WebSocket; using System; using System.Threading; using System.Threading.Tasks; namespace Discord.Interactions { /// /// Utility class containing helper methods for interacting with Discord Interactions. /// public static class InteractionUtility { /// /// Wait for an Interaction event for a given amount of time as an asynchronous opration. /// /// Client that should be listened to for the event. /// Timeout duration for this operation. /// Delegate for cheking whether an Interaction meets the requirements. /// Token for canceling the wait operation. /// /// A Task representing the asyncronous waiting operation. If the user responded in the given amount of time, Task result contains the user response, /// otherwise the Task result is . /// public static async Task WaitForInteractionAsync (BaseSocketClient client, TimeSpan timeout, Predicate predicate, CancellationToken cancellationToken = default) { var tcs = new TaskCompletionSource(); var waitCancelSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); Task wait = Task.Delay(timeout, waitCancelSource.Token) .ContinueWith((t) => { if (!t.IsCanceled) tcs.SetResult(null); }); cancellationToken.Register(( ) => tcs.SetCanceled()); client.InteractionCreated += HandleInteraction; var result = await tcs.Task.ConfigureAwait(false); client.InteractionCreated -= HandleInteraction; return result; Task HandleInteraction (SocketInteraction interaction) { if (predicate(interaction)) { waitCancelSource.Cancel(); tcs.SetResult(interaction); } return Task.CompletedTask; } } /// /// Wait for an Message Component Interaction event for a given amount of time as an asynchronous opration . /// /// Client that should be listened to for the event. /// The message that or should originate from. /// Timeout duration for this operation. /// Token for canceling the wait operation. /// /// A Task representing the asyncronous waiting operation with a result, /// the result is null if the process timed out before receiving a valid Interaction. /// public static Task WaitForMessageComponentAsync(BaseSocketClient client, IUserMessage fromMessage, TimeSpan timeout, CancellationToken cancellationToken = default) { bool Predicate (SocketInteraction interaction) => interaction is SocketMessageComponent component && component.Message.Id == fromMessage.Id; return WaitForInteractionAsync(client, timeout, Predicate, cancellationToken); } /// /// Create a confirmation dialog and wait for user input asynchronously. /// /// Client that should be listened to for the event. /// Send the confirmation prompt to this channel. /// Timeout duration of this operation. /// Optional custom prompt message. /// Token for canceling the wait operation. /// /// A Task representing the asyncronous waiting operation with a result, /// the result is if the user declined the prompt or didnt answer in time, if the user confirmed the prompt. /// public static async Task ConfirmAsync (BaseSocketClient client, IMessageChannel channel, TimeSpan timeout, string message = null, CancellationToken cancellationToken = default) { message ??= "Would you like to continue?"; var confirmId = $"confirm"; var declineId = $"decline"; var component = new ComponentBuilder() .WithButton("Confirm", confirmId, ButtonStyle.Success) .WithButton("Cancel", declineId, ButtonStyle.Danger) .Build(); var prompt = await channel.SendMessageAsync(message, components: component).ConfigureAwait(false); var response = await WaitForMessageComponentAsync(client, prompt, timeout, cancellationToken).ConfigureAwait(false) as SocketMessageComponent; await prompt.DeleteAsync().ConfigureAwait(false); if (response != null && response.Data.CustomId == confirmId) return true; else return false; } } }