You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

SocketInteraction.cs 8.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using Discord.Rest;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Model = Discord.API.Interaction;
  8. namespace Discord.WebSocket
  9. {
  10. /// <summary>
  11. /// Represents an Interaction recieved over the gateway.
  12. /// </summary>
  13. public abstract class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction
  14. {
  15. /// <summary>
  16. /// The <see cref="ISocketMessageChannel"/> this interaction was used in.
  17. /// </summary>
  18. public ISocketMessageChannel Channel { get; private set; }
  19. /// <summary>
  20. /// The <see cref="SocketUser"/> who triggered this interaction.
  21. /// </summary>
  22. public SocketUser User { get; private set; }
  23. /// <summary>
  24. /// The type of this interaction.
  25. /// </summary>
  26. public InteractionType Type { get; private set; }
  27. /// <summary>
  28. /// The token used to respond to this interaction.
  29. /// </summary>
  30. public string Token { get; private set; }
  31. /// <summary>
  32. /// The data sent with this interaction.
  33. /// </summary>
  34. public IDiscordInteractionData Data { get; private set; }
  35. /// <summary>
  36. /// The version of this interaction.
  37. /// </summary>
  38. public int Version { get; private set; }
  39. public DateTimeOffset CreatedAt { get; }
  40. /// <summary>
  41. /// <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/>.
  42. /// </summary>
  43. public bool IsValidToken
  44. => CheckToken();
  45. private ulong? GuildId { get; set; }
  46. private ulong? ChannelId { get; set; }
  47. internal SocketInteraction(DiscordSocketClient client, ulong id, ISocketMessageChannel channel)
  48. : base(client, id)
  49. {
  50. this.Channel = channel;
  51. }
  52. internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel)
  53. {
  54. if (model.Type == InteractionType.ApplicationCommand)
  55. return SocketSlashCommand.Create(client, model, channel);
  56. if (model.Type == InteractionType.MessageComponent)
  57. return SocketMessageComponent.Create(client, model, channel);
  58. else
  59. return null;
  60. }
  61. internal virtual void Update(Model model)
  62. {
  63. this.Data = model.Data.IsSpecified
  64. ? model.Data.Value
  65. : null;
  66. this.GuildId = model.GuildId.ToNullable();
  67. this.ChannelId = model.ChannelId.ToNullable();
  68. this.Token = model.Token;
  69. this.Version = model.Version;
  70. this.Type = model.Type;
  71. if (this.User == null)
  72. {
  73. if (model.Member.IsSpecified && model.GuildId.IsSpecified)
  74. {
  75. this.User = SocketGuildUser.Create(Discord.State.GetGuild(this.GuildId.Value), Discord.State, model.Member.Value);
  76. }
  77. else
  78. {
  79. this.User = SocketGlobalUser.Create(this.Discord, this.Discord.State, model.User.Value);
  80. }
  81. }
  82. }
  83. /// <summary>
  84. /// Responds to an Interaction.
  85. /// <para>
  86. /// If you have <see cref="DiscordSocketConfig.AlwaysAcknowledgeInteractions"/> set to <see langword="true"/>, You should use
  87. /// <see cref="FollowupAsync(string, bool, Embed, InteractionResponseType, AllowedMentions, RequestOptions)"/> instead.
  88. /// </para>
  89. /// </summary>
  90. /// <param name="text">The text of the message to be sent.</param>
  91. /// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param>
  92. /// <param name="embed">A <see cref="Embed"/> to send with this response.</param>
  93. /// <param name="type">The type of response to this Interaction.</param>
  94. /// <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param>
  95. /// <param name="allowedMentions">The allowed mentions for this response.</param>
  96. /// <param name="options">The request options for this response.</param>
  97. /// <param name="component">A <see cref="MessageComponent"/> to be sent with this response</param>
  98. /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
  99. /// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception>
  100. public abstract Task RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource,
  101. bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null);
  102. /// <summary>
  103. /// Sends a followup message for this interaction.
  104. /// </summary>
  105. /// <param name="text">The text of the message to be sent</param>
  106. /// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param>
  107. /// <param name="embed">A <see cref="Embed"/> to send with this response.</param>
  108. /// <param name="type">The type of response to this Interaction.</param>
  109. /// /// <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param>
  110. /// <param name="allowedMentions">The allowed mentions for this response.</param>
  111. /// <param name="options">The request options for this response.</param>
  112. /// <param name="component">A <see cref="MessageComponent"/> to be sent with this response</param>
  113. /// <returns>
  114. /// The sent message.
  115. /// </returns>
  116. public abstract Task<RestFollowupMessage> FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, bool ephemeral = false,
  117. InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource,
  118. AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null);
  119. /// <summary>
  120. /// Gets the original response for this interaction.
  121. /// </summary>
  122. /// <param name="options">The request options for this async request.</param>
  123. /// <returns>A <see cref="RestInteractionMessage"/> that represents the intitial response, or <see langword="null"/> if there is no response.</returns>
  124. public Task<RestInteractionMessage> GetOriginalResponseAsync(RequestOptions options = null)
  125. {
  126. return InteractionHelper.GetOriginalResponseAsync(this.Discord, this.Channel, this, options);
  127. }
  128. /// <summary>
  129. /// Acknowledges this interaction with the <see cref="InteractionResponseType.DeferredChannelMessageWithSource"/>.
  130. /// </summary>
  131. /// <returns>
  132. /// A task that represents the asynchronous operation of acknowledging the interaction.
  133. /// </returns>
  134. public virtual Task AcknowledgeAsync(RequestOptions options = null)
  135. {
  136. var response = new API.InteractionResponse()
  137. {
  138. Type = InteractionResponseType.DeferredChannelMessageWithSource,
  139. };
  140. return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options);
  141. }
  142. private bool CheckToken()
  143. {
  144. // Tokens last for 15 minutes according to https://discord.com/developers/docs/interactions/slash-commands#responding-to-an-interaction
  145. return (DateTime.UtcNow - this.CreatedAt.UtcDateTime).TotalMinutes >= 15d;
  146. }
  147. }
  148. }