using Discord.Rest; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Model = Discord.API.Interaction; namespace Discord.WebSocket { /// /// Represents an Interaction recieved over the gateway. /// public abstract class SocketInteraction : SocketEntity, IDiscordInteraction { /// /// The this interaction was used in. /// public ISocketMessageChannel Channel { get; private set; } /// /// The who triggered this interaction. /// public SocketUser User { get; private set; } /// /// The type of this interaction. /// public InteractionType Type { get; private set; } /// /// The token used to respond to this interaction. /// public string Token { get; private set; } /// /// The data sent with this interaction. /// public IDiscordInteractionData Data { get; private set; } /// /// The version of this interaction. /// public int Version { get; private set; } public DateTimeOffset CreatedAt { get; } /// /// if the token is valid for replying to, otherwise . /// public bool IsValidToken => CheckToken(); private ulong? GuildId { get; set; } private ulong? ChannelId { get; set; } internal SocketInteraction(DiscordSocketClient client, ulong id, ISocketMessageChannel channel) : base(client, id) { this.Channel = channel; } internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) { if (model.Type == InteractionType.ApplicationCommand) return SocketSlashCommand.Create(client, model, channel); if (model.Type == InteractionType.MessageComponent) return SocketMessageComponent.Create(client, model, channel); else return null; } internal virtual void Update(Model model) { this.Data = model.Data.IsSpecified ? model.Data.Value : null; this.GuildId = model.GuildId.ToNullable(); this.ChannelId = model.ChannelId.ToNullable(); this.Token = model.Token; this.Version = model.Version; this.Type = model.Type; if (this.User == null) { if (model.Member.IsSpecified && model.GuildId.IsSpecified) { this.User = SocketGuildUser.Create(Discord.State.GetGuild(this.GuildId.Value), Discord.State, model.Member.Value); } else { this.User = SocketGlobalUser.Create(this.Discord, this.Discord.State, model.User.Value); } } } /// /// Responds to an Interaction. /// /// If you have set to , You should use /// instead. /// /// /// The text of the message to be sent. /// if the message should be read out by a text-to-speech reader, otherwise . /// A to send with this response. /// The type of response to this Interaction. /// if the response should be hidden to everyone besides the invoker of the command, otherwise . /// The allowed mentions for this response. /// The request options for this response. /// A to be sent with this response /// Message content is too long, length must be less or equal to . /// The parameters provided were invalid or the token was invalid. public abstract Task RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null); /// /// Sends a followup message for this interaction. /// /// The text of the message to be sent /// if the message should be read out by a text-to-speech reader, otherwise . /// A to send with this response. /// The type of response to this Interaction. /// /// if the response should be hidden to everyone besides the invoker of the command, otherwise . /// The allowed mentions for this response. /// The request options for this response. /// A to be sent with this response /// /// The sent message. /// public abstract Task FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, bool ephemeral = false, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null); /// /// Gets the original response for this interaction. /// /// The request options for this async request. /// A that represents the intitial response, or if there is no response. public Task GetOriginalResponseAsync(RequestOptions options = null) { return InteractionHelper.GetOriginalResponseAsync(this.Discord, this.Channel, this, options); } /// /// Acknowledges this interaction with the . /// /// /// A task that represents the asynchronous operation of acknowledging the interaction. /// public virtual Task AcknowledgeAsync(RequestOptions options = null) { var response = new API.InteractionResponse() { Type = InteractionResponseType.DeferredChannelMessageWithSource, }; return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); } private bool CheckToken() { // Tokens last for 15 minutes according to https://discord.com/developers/docs/interactions/slash-commands#responding-to-an-interaction return (DateTime.UtcNow - this.CreatedAt.UtcDateTime).TotalMinutes >= 15d; } } }