feature: optional API calling to RestInteraction (#2281)
* Take 2 * Expose channel & guild Id for manual calling * Make api calling optional at runtime * Resolve build errors * Bind runtime option to interaction type * Expose methods to get channel & guild from API * Patch out NRE's, test on all int types
This commit is contained in:
@@ -32,9 +32,15 @@ namespace Discord.Rest
|
|||||||
/// Initializes a new <see cref="DiscordRestClient"/> with the provided configuration.
|
/// Initializes a new <see cref="DiscordRestClient"/> with the provided configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config">The configuration to be used with the client.</param>
|
/// <param name="config">The configuration to be used with the client.</param>
|
||||||
public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClient(config)) { }
|
public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClient(config))
|
||||||
|
{
|
||||||
|
_apiOnCreation = config.APIOnRestInteractionCreation;
|
||||||
|
}
|
||||||
// used for socket client rest access
|
// used for socket client rest access
|
||||||
internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api) { }
|
internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api)
|
||||||
|
{
|
||||||
|
_apiOnCreation = config.APIOnRestInteractionCreation;
|
||||||
|
}
|
||||||
|
|
||||||
private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config)
|
private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config)
|
||||||
=> new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, serializer: Serializer, useSystemClock: config.UseSystemClock, defaultRatelimitCallback: config.DefaultRatelimitCallback);
|
=> new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, serializer: Serializer, useSystemClock: config.UseSystemClock, defaultRatelimitCallback: config.DefaultRatelimitCallback);
|
||||||
@@ -82,6 +88,8 @@ namespace Discord.Rest
|
|||||||
|
|
||||||
#region Rest interactions
|
#region Rest interactions
|
||||||
|
|
||||||
|
private readonly bool _apiOnCreation;
|
||||||
|
|
||||||
public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, string body)
|
public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, string body)
|
||||||
=> IsValidHttpInteraction(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body));
|
=> IsValidHttpInteraction(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body));
|
||||||
public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, byte[] body)
|
public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, byte[] body)
|
||||||
@@ -113,8 +121,8 @@ namespace Discord.Rest
|
|||||||
/// A <see cref="RestInteraction"/> that represents the incoming http interaction.
|
/// A <see cref="RestInteraction"/> that represents the incoming http interaction.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <exception cref="BadSignatureException">Thrown when the signature doesn't match the public key.</exception>
|
/// <exception cref="BadSignatureException">Thrown when the signature doesn't match the public key.</exception>
|
||||||
public Task<RestInteraction> ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, string body)
|
public Task<RestInteraction> ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, string body, Func<InteractionType, bool> doApiCallOnCreation = null)
|
||||||
=> ParseHttpInteractionAsync(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body));
|
=> ParseHttpInteractionAsync(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body), doApiCallOnCreation);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="RestInteraction"/> from a http message.
|
/// Creates a <see cref="RestInteraction"/> from a http message.
|
||||||
@@ -127,7 +135,7 @@ namespace Discord.Rest
|
|||||||
/// A <see cref="RestInteraction"/> that represents the incoming http interaction.
|
/// A <see cref="RestInteraction"/> that represents the incoming http interaction.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <exception cref="BadSignatureException">Thrown when the signature doesn't match the public key.</exception>
|
/// <exception cref="BadSignatureException">Thrown when the signature doesn't match the public key.</exception>
|
||||||
public async Task<RestInteraction> ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, byte[] body)
|
public async Task<RestInteraction> ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, byte[] body, Func<InteractionType, bool> doApiCallOnCreation = null)
|
||||||
{
|
{
|
||||||
if (!IsValidHttpInteraction(publicKey, signature, timestamp, body))
|
if (!IsValidHttpInteraction(publicKey, signature, timestamp, body))
|
||||||
{
|
{
|
||||||
@@ -138,12 +146,12 @@ namespace Discord.Rest
|
|||||||
using (var jsonReader = new JsonTextReader(textReader))
|
using (var jsonReader = new JsonTextReader(textReader))
|
||||||
{
|
{
|
||||||
var model = Serializer.Deserialize<API.Interaction>(jsonReader);
|
var model = Serializer.Deserialize<API.Interaction>(jsonReader);
|
||||||
return await RestInteraction.CreateAsync(this, model);
|
return await RestInteraction.CreateAsync(this, model, doApiCallOnCreation != null ? doApiCallOnCreation(model.Type) : _apiOnCreation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public async Task<RestApplication> GetApplicationInfoAsync(RequestOptions options = null)
|
public async Task<RestApplication> GetApplicationInfoAsync(RequestOptions options = null)
|
||||||
{
|
{
|
||||||
return _applicationInfo ??= await ClientHelper.GetApplicationInfoAsync(this, options).ConfigureAwait(false);
|
return _applicationInfo ??= await ClientHelper.GetApplicationInfoAsync(this, options).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -9,5 +9,7 @@ namespace Discord.Rest
|
|||||||
{
|
{
|
||||||
/// <summary> Gets or sets the provider used to generate new REST connections. </summary>
|
/// <summary> Gets or sets the provider used to generate new REST connections. </summary>
|
||||||
public RestClientProvider RestClientProvider { get; set; } = DefaultRestClientProvider.Instance;
|
public RestClientProvider RestClientProvider { get; set; } = DefaultRestClientProvider.Instance;
|
||||||
|
|
||||||
|
public bool APIOnRestInteractionCreation { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,16 +39,16 @@ namespace Discord.Rest
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new static async Task<RestCommandBase> CreateAsync(DiscordRestClient client, Model model)
|
internal new static async Task<RestCommandBase> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestCommandBase(client, model);
|
var entity = new RestCommandBase(client, model);
|
||||||
await entity.UpdateAsync(client, model).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override async Task UpdateAsync(DiscordRestClient client, Model model)
|
internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
await base.UpdateAsync(client, model).ConfigureAwait(false);
|
await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -27,20 +27,20 @@ namespace Discord.Rest
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<RestCommandBaseData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
|
internal static async Task<RestCommandBaseData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestCommandBaseData(client, model);
|
var entity = new RestCommandBaseData(client, model);
|
||||||
await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
|
internal virtual async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
|
||||||
{
|
{
|
||||||
Name = model.Name;
|
Name = model.Name;
|
||||||
if (model.Resolved.IsSpecified && ResolvableData == null)
|
if (model.Resolved.IsSpecified && ResolvableData == null)
|
||||||
{
|
{
|
||||||
ResolvableData = new RestResolvableData<Model>();
|
ResolvableData = new RestResolvableData<Model>();
|
||||||
await ResolvableData.PopulateAsync(client, guild, channel, model).ConfigureAwait(false);
|
await ResolvableData.PopulateAsync(client, guild, channel, model, doApiCall).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Discord.Rest
|
|||||||
internal readonly Dictionary<ulong, Attachment> Attachments
|
internal readonly Dictionary<ulong, Attachment> Attachments
|
||||||
= new Dictionary<ulong, Attachment>();
|
= new Dictionary<ulong, Attachment>();
|
||||||
|
|
||||||
internal async Task PopulateAsync(DiscordRestClient discord, RestGuild guild, IRestMessageChannel channel, T model)
|
internal async Task PopulateAsync(DiscordRestClient discord, RestGuild guild, IRestMessageChannel channel, T model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var resolved = model.Resolved.Value;
|
var resolved = model.Resolved.Value;
|
||||||
|
|
||||||
@@ -38,15 +38,26 @@ namespace Discord.Rest
|
|||||||
|
|
||||||
if (resolved.Channels.IsSpecified)
|
if (resolved.Channels.IsSpecified)
|
||||||
{
|
{
|
||||||
var channels = await guild.GetChannelsAsync().ConfigureAwait(false);
|
var channels = doApiCall ? await guild.GetChannelsAsync().ConfigureAwait(false) : null;
|
||||||
|
|
||||||
foreach (var channelModel in resolved.Channels.Value)
|
foreach (var channelModel in resolved.Channels.Value)
|
||||||
{
|
{
|
||||||
var restChannel = channels.FirstOrDefault(x => x.Id == channelModel.Value.Id);
|
if (channels != null)
|
||||||
|
{
|
||||||
|
var guildChannel = channels.FirstOrDefault(x => x.Id == channelModel.Value.Id);
|
||||||
|
|
||||||
restChannel.Update(channelModel.Value);
|
guildChannel.Update(channelModel.Value);
|
||||||
|
|
||||||
Channels.Add(ulong.Parse(channelModel.Key), restChannel);
|
Channels.Add(ulong.Parse(channelModel.Key), guildChannel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var restChannel = RestChannel.Create(discord, channelModel.Value);
|
||||||
|
|
||||||
|
restChannel.Update(channelModel.Value);
|
||||||
|
|
||||||
|
Channels.Add(ulong.Parse(channelModel.Key), restChannel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +87,10 @@ namespace Discord.Rest
|
|||||||
{
|
{
|
||||||
foreach (var msg in resolved.Messages.Value)
|
foreach (var msg in resolved.Messages.Value)
|
||||||
{
|
{
|
||||||
channel ??= (IRestMessageChannel)(Channels.FirstOrDefault(x => x.Key == msg.Value.ChannelId).Value ?? await discord.GetChannelAsync(msg.Value.ChannelId).ConfigureAwait(false));
|
channel ??= (IRestMessageChannel)(Channels.FirstOrDefault(x => x.Key == msg.Value.ChannelId).Value
|
||||||
|
?? (doApiCall
|
||||||
|
? await discord.GetChannelAsync(msg.Value.ChannelId).ConfigureAwait(false)
|
||||||
|
: null));
|
||||||
|
|
||||||
RestUser author;
|
RestUser author;
|
||||||
|
|
||||||
|
|||||||
@@ -20,22 +20,22 @@ namespace Discord.Rest
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new static async Task<RestMessageCommand> CreateAsync(DiscordRestClient client, Model model)
|
internal new static async Task<RestMessageCommand> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestMessageCommand(client, model);
|
var entity = new RestMessageCommand(client, model);
|
||||||
await entity.UpdateAsync(client, model).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override async Task UpdateAsync(DiscordRestClient client, Model model)
|
internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
await base.UpdateAsync(client, model).ConfigureAwait(false);
|
await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
var dataModel = model.Data.IsSpecified
|
var dataModel = model.Data.IsSpecified
|
||||||
? (DataModel)model.Data.Value
|
? (DataModel)model.Data.Value
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
Data = await RestMessageCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false);
|
Data = await RestMessageCommandData.CreateAsync(client, dataModel, Guild, Channel, doApiCall).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//IMessageCommandInteraction
|
//IMessageCommandInteraction
|
||||||
|
|||||||
@@ -23,15 +23,15 @@ namespace Discord.Rest
|
|||||||
/// <b>Note</b> Not implemented for <see cref="RestMessageCommandData"/>
|
/// <b>Note</b> Not implemented for <see cref="RestMessageCommandData"/>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public override IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options
|
public override IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options
|
||||||
=> throw new System.NotImplementedException();
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
internal RestMessageCommandData(DiscordRestClient client, Model model)
|
internal RestMessageCommandData(DiscordRestClient client, Model model)
|
||||||
: base(client, model) { }
|
: base(client, model) { }
|
||||||
|
|
||||||
internal new static async Task<RestMessageCommandData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
|
internal new static async Task<RestMessageCommandData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestMessageCommandData(client, model);
|
var entity = new RestMessageCommandData(client, model);
|
||||||
await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,22 +23,22 @@ namespace Discord.Rest
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new static async Task<RestUserCommand> CreateAsync(DiscordRestClient client, Model model)
|
internal new static async Task<RestUserCommand> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestUserCommand(client, model);
|
var entity = new RestUserCommand(client, model);
|
||||||
await entity.UpdateAsync(client, model).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override async Task UpdateAsync(DiscordRestClient client, Model model)
|
internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
await base.UpdateAsync(client, model).ConfigureAwait(false);
|
await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
var dataModel = model.Data.IsSpecified
|
var dataModel = model.Data.IsSpecified
|
||||||
? (DataModel)model.Data.Value
|
? (DataModel)model.Data.Value
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
Data = await RestUserCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false);
|
Data = await RestUserCommandData.CreateAsync(client, dataModel, Guild, Channel, doApiCall).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//IUserCommandInteractionData
|
//IUserCommandInteractionData
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ namespace Discord.Rest
|
|||||||
internal RestUserCommandData(DiscordRestClient client, Model model)
|
internal RestUserCommandData(DiscordRestClient client, Model model)
|
||||||
: base(client, model) { }
|
: base(client, model) { }
|
||||||
|
|
||||||
internal new static async Task<RestUserCommandData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
|
internal new static async Task<RestUserCommandData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestUserCommandData(client, model);
|
var entity = new RestUserCommandData(client, model);
|
||||||
await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,15 +37,15 @@ namespace Discord.Rest
|
|||||||
Data = new RestMessageComponentData(dataModel);
|
Data = new RestMessageComponentData(dataModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new static async Task<RestMessageComponent> CreateAsync(DiscordRestClient client, Model model)
|
internal new static async Task<RestMessageComponent> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestMessageComponent(client, model);
|
var entity = new RestMessageComponent(client, model);
|
||||||
await entity.UpdateAsync(client, model).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
internal override async Task UpdateAsync(DiscordRestClient discord, Model model)
|
internal override async Task UpdateAsync(DiscordRestClient discord, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
await base.UpdateAsync(discord, model).ConfigureAwait(false);
|
await base.UpdateAsync(discord, model, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
if (model.Message.IsSpecified && model.ChannelId.IsSpecified)
|
if (model.Message.IsSpecified && model.ChannelId.IsSpecified)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ namespace Discord.Rest
|
|||||||
Data = new RestModalData(dataModel);
|
Data = new RestModalData(dataModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new static async Task<RestModal> CreateAsync(DiscordRestClient client, ModelBase model)
|
internal new static async Task<RestModal> CreateAsync(DiscordRestClient client, ModelBase model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestModal(client, model);
|
var entity = new RestModal(client, model);
|
||||||
await entity.UpdateAsync(client, model);
|
await entity.UpdateAsync(client, model, doApiCall);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ namespace Discord.Rest
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class RestInteraction : RestEntity<ulong>, IDiscordInteraction
|
public abstract class RestInteraction : RestEntity<ulong>, IDiscordInteraction
|
||||||
{
|
{
|
||||||
|
// Added so channel & guild methods don't need a client reference
|
||||||
|
private Func<RequestOptions, ulong, Task<IRestMessageChannel>> _getChannel = null;
|
||||||
|
private Func<RequestOptions, ulong, Task<RestGuild>> _getGuild = null;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public InteractionType Type { get; private set; }
|
public InteractionType Type { get; private set; }
|
||||||
|
|
||||||
@@ -31,6 +35,10 @@ namespace Discord.Rest
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user who invoked the interaction.
|
/// Gets the user who invoked the interaction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If this user is an <see cref="RestGuildUser"/> and <see cref="DiscordRestConfig.APIOnRestInteractionCreation"/> is set to false,
|
||||||
|
/// <see cref="RestGuildUser.Guild"/> will return <see langword="null"/>
|
||||||
|
/// </remarks>
|
||||||
public RestUser User { get; private set; }
|
public RestUser User { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -48,14 +56,38 @@ namespace Discord.Rest
|
|||||||
public bool IsValidToken
|
public bool IsValidToken
|
||||||
=> InteractionHelper.CanRespondOrFollowup(this);
|
=> InteractionHelper.CanRespondOrFollowup(this);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ID of the channel this interaction was executed in.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <see langword="null"/> if the interaction was not executed in a guild.
|
||||||
|
/// </remarks>
|
||||||
|
public ulong? ChannelId { get; private set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the channel that this interaction was executed in.
|
/// Gets the channel that this interaction was executed in.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <see langword="null"/> if <see cref="DiscordRestConfig.APIOnRestInteractionCreation"/> is set to false.
|
||||||
|
/// Call <see cref="GetChannelAsync"/> to set this property and get the interaction channel.
|
||||||
|
/// </remarks>
|
||||||
public IRestMessageChannel Channel { get; private set; }
|
public IRestMessageChannel Channel { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the guild this interaction was executed in.
|
/// Gets the ID of the guild this interaction was executed in if applicable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <see langword="null"/> if the interaction was not executed in a guild.
|
||||||
|
/// </remarks>
|
||||||
|
public ulong? GuildId { get; private set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the guild this interaction was executed in if applicable.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This property will be <see langword="null"/> if <see cref="DiscordRestConfig.APIOnRestInteractionCreation"/> is set to false
|
||||||
|
/// or if the interaction was not executed in a guild.
|
||||||
|
/// </remarks>
|
||||||
public RestGuild Guild { get; private set; }
|
public RestGuild Guild { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -72,11 +104,11 @@ namespace Discord.Rest
|
|||||||
: DateTime.UtcNow;
|
: DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<RestInteraction> CreateAsync(DiscordRestClient client, Model model)
|
internal static async Task<RestInteraction> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
if(model.Type == InteractionType.Ping)
|
if(model.Type == InteractionType.Ping)
|
||||||
{
|
{
|
||||||
return await RestPingInteraction.CreateAsync(client, model);
|
return await RestPingInteraction.CreateAsync(client, model, doApiCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.Type == InteractionType.ApplicationCommand)
|
if (model.Type == InteractionType.ApplicationCommand)
|
||||||
@@ -90,26 +122,26 @@ namespace Discord.Rest
|
|||||||
|
|
||||||
return dataModel.Type switch
|
return dataModel.Type switch
|
||||||
{
|
{
|
||||||
ApplicationCommandType.Slash => await RestSlashCommand.CreateAsync(client, model).ConfigureAwait(false),
|
ApplicationCommandType.Slash => await RestSlashCommand.CreateAsync(client, model, doApiCall).ConfigureAwait(false),
|
||||||
ApplicationCommandType.Message => await RestMessageCommand.CreateAsync(client, model).ConfigureAwait(false),
|
ApplicationCommandType.Message => await RestMessageCommand.CreateAsync(client, model, doApiCall).ConfigureAwait(false),
|
||||||
ApplicationCommandType.User => await RestUserCommand.CreateAsync(client, model).ConfigureAwait(false),
|
ApplicationCommandType.User => await RestUserCommand.CreateAsync(client, model, doApiCall).ConfigureAwait(false),
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.Type == InteractionType.MessageComponent)
|
if (model.Type == InteractionType.MessageComponent)
|
||||||
return await RestMessageComponent.CreateAsync(client, model).ConfigureAwait(false);
|
return await RestMessageComponent.CreateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
if (model.Type == InteractionType.ApplicationCommandAutocomplete)
|
if (model.Type == InteractionType.ApplicationCommandAutocomplete)
|
||||||
return await RestAutocompleteInteraction.CreateAsync(client, model).ConfigureAwait(false);
|
return await RestAutocompleteInteraction.CreateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
if (model.Type == InteractionType.ModalSubmit)
|
if (model.Type == InteractionType.ModalSubmit)
|
||||||
return await RestModal.CreateAsync(client, model).ConfigureAwait(false);
|
return await RestModal.CreateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual async Task UpdateAsync(DiscordRestClient discord, Model model)
|
internal virtual async Task UpdateAsync(DiscordRestClient discord, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
IsDMInteraction = !model.GuildId.IsSpecified;
|
IsDMInteraction = !model.GuildId.IsSpecified;
|
||||||
|
|
||||||
@@ -120,16 +152,23 @@ namespace Discord.Rest
|
|||||||
Version = model.Version;
|
Version = model.Version;
|
||||||
Type = model.Type;
|
Type = model.Type;
|
||||||
|
|
||||||
if(Guild == null && model.GuildId.IsSpecified)
|
if (Guild == null && model.GuildId.IsSpecified)
|
||||||
{
|
{
|
||||||
Guild = await discord.GetGuildAsync(model.GuildId.Value);
|
GuildId = model.GuildId.Value;
|
||||||
|
if (doApiCall)
|
||||||
|
Guild = await discord.GetGuildAsync(model.GuildId.Value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Guild = null;
|
||||||
|
_getGuild = new(async (opt, ul) => await discord.GetGuildAsync(ul, opt));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (User == null)
|
if (User == null)
|
||||||
{
|
{
|
||||||
if (model.Member.IsSpecified && model.GuildId.IsSpecified)
|
if (model.Member.IsSpecified && model.GuildId.IsSpecified)
|
||||||
{
|
{
|
||||||
User = RestGuildUser.Create(Discord, Guild, model.Member.Value);
|
User = RestGuildUser.Create(Discord, Guild, model.Member.Value, (Guild is null) ? model.GuildId.Value : null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -137,18 +176,33 @@ namespace Discord.Rest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Channel == null && model.ChannelId.IsSpecified)
|
if (Channel == null && model.ChannelId.IsSpecified)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value);
|
ChannelId = model.ChannelId.Value;
|
||||||
|
if (doApiCall)
|
||||||
|
Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_getChannel = new(async (opt, ul) =>
|
||||||
|
{
|
||||||
|
if (Guild is null)
|
||||||
|
return (IRestMessageChannel)await discord.GetChannelAsync(ul, opt);
|
||||||
|
else // get a guild channel if the guild is set.
|
||||||
|
return (IRestMessageChannel)await Guild.GetChannelAsync(ul, opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
Channel = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(HttpException x) when(x.DiscordCode == DiscordErrorCode.MissingPermissions) { } // ignore
|
catch (HttpException x) when (x.DiscordCode == DiscordErrorCode.MissingPermissions) { } // ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
UserLocale = model.UserLocale.IsSpecified
|
UserLocale = model.UserLocale.IsSpecified
|
||||||
? model.UserLocale.Value
|
? model.UserLocale.Value
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
GuildLocale = model.GuildLocale.IsSpecified
|
GuildLocale = model.GuildLocale.IsSpecified
|
||||||
? model.GuildLocale.Value
|
? model.GuildLocale.Value
|
||||||
: null;
|
: null;
|
||||||
@@ -164,6 +218,59 @@ namespace Discord.Rest
|
|||||||
return json.ToString();
|
return json.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel this interaction was executed in. Will be a DM channel if the interaction was executed in DM.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Calling this method succesfully will populate the <see cref="Channel"/> property.
|
||||||
|
/// After this, further calls to this method will no longer call the API, and depend on the value set in <see cref="Channel"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="options">The request options for this <see langword="async"/> request.</param>
|
||||||
|
/// <returns>A Rest channel to send messages to.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown if no channel can be received.</exception>
|
||||||
|
public async Task<IRestMessageChannel> GetChannelAsync(RequestOptions options = null)
|
||||||
|
{
|
||||||
|
if (IsDMInteraction && Channel is null)
|
||||||
|
{
|
||||||
|
var channel = await User.CreateDMChannelAsync(options);
|
||||||
|
Channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (Channel is null)
|
||||||
|
{
|
||||||
|
var channel = await _getChannel(options, ChannelId.Value);
|
||||||
|
|
||||||
|
if (channel is null)
|
||||||
|
throw new InvalidOperationException("The interaction channel was not able to be retrieved.");
|
||||||
|
Channel = channel;
|
||||||
|
|
||||||
|
_getChannel = null; // get rid of it, we don't need it anymore.
|
||||||
|
}
|
||||||
|
|
||||||
|
return Channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the guild this interaction was executed in if applicable.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Calling this method succesfully will populate the <see cref="Guild"/> property.
|
||||||
|
/// After this, further calls to this method will no longer call the API, and depend on the value set in <see cref="Guild"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="options">The request options for this <see langword="async"/> request.</param>
|
||||||
|
/// <returns>The guild this interaction was executed in. <see langword="null"/> if the interaction was executed inside DM.</returns>
|
||||||
|
public async Task<RestGuild> GetGuildAsync(RequestOptions options)
|
||||||
|
{
|
||||||
|
if (IsDMInteraction)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (Guild is null)
|
||||||
|
Guild = await _getGuild(options, GuildId.Value);
|
||||||
|
|
||||||
|
_getGuild = null; // get rid of it, we don't need it anymore.
|
||||||
|
return Guild;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract string Defer(bool ephemeral = false, RequestOptions options = null);
|
public abstract string Defer(bool ephemeral = false, RequestOptions options = null);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ namespace Discord.Rest
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static new async Task<RestPingInteraction> CreateAsync(DiscordRestClient client, Model model)
|
internal static new async Task<RestPingInteraction> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestPingInteraction(client, model.Id);
|
var entity = new RestPingInteraction(client, model.Id);
|
||||||
await entity.UpdateAsync(client, model);
|
await entity.UpdateAsync(client, model, doApiCall);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ namespace Discord.Rest
|
|||||||
Data = new RestAutocompleteInteractionData(dataModel);
|
Data = new RestAutocompleteInteractionData(dataModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new static async Task<RestAutocompleteInteraction> CreateAsync(DiscordRestClient client, Model model)
|
internal new static async Task<RestAutocompleteInteraction> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestAutocompleteInteraction(client, model);
|
var entity = new RestAutocompleteInteraction(client, model);
|
||||||
await entity.UpdateAsync(client, model).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,22 +23,22 @@ namespace Discord.Rest
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new static async Task<RestSlashCommand> CreateAsync(DiscordRestClient client, Model model)
|
internal new static async Task<RestSlashCommand> CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestSlashCommand(client, model);
|
var entity = new RestSlashCommand(client, model);
|
||||||
await entity.UpdateAsync(client, model).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override async Task UpdateAsync(DiscordRestClient client, Model model)
|
internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
|
||||||
{
|
{
|
||||||
await base.UpdateAsync(client, model).ConfigureAwait(false);
|
await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
var dataModel = model.Data.IsSpecified
|
var dataModel = model.Data.IsSpecified
|
||||||
? (DataModel)model.Data.Value
|
? (DataModel)model.Data.Value
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
Data = await RestSlashCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false);
|
Data = await RestSlashCommandData.CreateAsync(client, dataModel, Guild, Channel, doApiCall).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ISlashCommandInteraction
|
//ISlashCommandInteraction
|
||||||
|
|||||||
@@ -14,15 +14,15 @@ namespace Discord.Rest
|
|||||||
internal RestSlashCommandData(DiscordRestClient client, Model model)
|
internal RestSlashCommandData(DiscordRestClient client, Model model)
|
||||||
: base(client, model) { }
|
: base(client, model) { }
|
||||||
|
|
||||||
internal static new async Task<RestSlashCommandData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
|
internal static new async Task<RestSlashCommandData> CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
|
||||||
{
|
{
|
||||||
var entity = new RestSlashCommandData(client, model);
|
var entity = new RestSlashCommandData(client, model);
|
||||||
await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
|
await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
internal override async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
|
internal override async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
|
||||||
{
|
{
|
||||||
await base.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
|
await base.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
|
||||||
|
|
||||||
Options = model.Options.IsSpecified
|
Options = model.Options.IsSpecified
|
||||||
? model.Options.Value.Select(x => new RestSlashCommandDataOption(this, x)).ToImmutableArray()
|
? model.Options.Value.Select(x => new RestSlashCommandDataOption(this, x)).ToImmutableArray()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace Discord.Rest
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DateTimeOffset? PremiumSince => DateTimeUtils.FromTicks(_premiumSinceTicks);
|
public DateTimeOffset? PremiumSince => DateTimeUtils.FromTicks(_premiumSinceTicks);
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ulong GuildId => Guild.Id;
|
public ulong GuildId { get; }
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool? IsPending { get; private set; }
|
public bool? IsPending { get; private set; }
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -80,14 +80,16 @@ namespace Discord.Rest
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks);
|
public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks);
|
||||||
|
|
||||||
internal RestGuildUser(BaseDiscordClient discord, IGuild guild, ulong id)
|
internal RestGuildUser(BaseDiscordClient discord, IGuild guild, ulong id, ulong? guildId = null)
|
||||||
: base(discord, id)
|
: base(discord, id)
|
||||||
{
|
{
|
||||||
Guild = guild;
|
if (guild is not null)
|
||||||
|
Guild = guild;
|
||||||
|
GuildId = guildId ?? Guild.Id;
|
||||||
}
|
}
|
||||||
internal static RestGuildUser Create(BaseDiscordClient discord, IGuild guild, Model model)
|
internal static RestGuildUser Create(BaseDiscordClient discord, IGuild guild, Model model, ulong? guildId = null)
|
||||||
{
|
{
|
||||||
var entity = new RestGuildUser(discord, guild, model.User.Id);
|
var entity = new RestGuildUser(discord, guild, model.User.Id, guildId);
|
||||||
entity.Update(model);
|
entity.Update(model);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
@@ -116,7 +118,7 @@ namespace Discord.Rest
|
|||||||
private void UpdateRoles(ulong[] roleIds)
|
private void UpdateRoles(ulong[] roleIds)
|
||||||
{
|
{
|
||||||
var roles = ImmutableArray.CreateBuilder<ulong>(roleIds.Length + 1);
|
var roles = ImmutableArray.CreateBuilder<ulong>(roleIds.Length + 1);
|
||||||
roles.Add(Guild.Id);
|
roles.Add(GuildId);
|
||||||
for (int i = 0; i < roleIds.Length; i++)
|
for (int i = 0; i < roleIds.Length; i++)
|
||||||
roles.Add(roleIds[i]);
|
roles.Add(roleIds[i]);
|
||||||
_roleIds = roles.ToImmutable();
|
_roleIds = roles.ToImmutable();
|
||||||
|
|||||||
Reference in New Issue
Block a user