Skip to content

Commit

Permalink
feature: Webhook support for threads (#2291)
Browse files Browse the repository at this point in the history
* Added thread support to webhooks

Added thread support to delete/send messages for webhooks

* Revert "Added thread support to webhooks"

This reverts commit c45ef38.

* read added threads as im a dummy

* fixed formating

* Fixed modify EmbedMessage
  • Loading branch information
openmilk committed May 13, 2022
1 parent 20ffa64 commit b0a3b65
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 47 deletions.
52 changes: 35 additions & 17 deletions src/Discord.Net.Rest/DiscordRestApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,12 @@ public async Task LogoutAsync()
private async Task LogoutInternalAsync()
{
//An exception here will lock the client into the unusable LoggingOut state, but that's probably fine since our client is in an undefined state too.
if (LoginState == LoginState.LoggedOut) return;
if (LoginState == LoginState.LoggedOut)
return;
LoginState = LoginState.LoggingOut;

try { _loginCancelToken?.Cancel(false); }
try
{ _loginCancelToken?.Cancel(false); }
catch { }

await DisconnectInternalAsync(null).ConfigureAwait(false);
Expand Down Expand Up @@ -398,7 +400,7 @@ public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, Rest.ModifyG
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));

if(args.Name.IsSpecified)
if (args.Name.IsSpecified)
Preconditions.AtMost(args.Name.Value.Length, 100, nameof(args.Name));

options = RequestOptions.CreateOrClone(options);
Expand All @@ -414,9 +416,9 @@ public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, Rest.ModifyT
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));

if(args.Name.IsSpecified)
if (args.Name.IsSpecified)
Preconditions.AtMost(args.Name.Value.Length, 100, nameof(args.Name));
if(args.Topic.IsSpecified)
if (args.Topic.IsSpecified)
Preconditions.AtMost(args.Topic.Value.Length, 1024, nameof(args.Name));

Preconditions.AtLeast(args.SlowModeInterval, 0, nameof(args.SlowModeInterval));
Expand Down Expand Up @@ -798,9 +800,11 @@ public async Task<Message> CreateMessageAsync(ulong channelId, CreateMessagePara
var ids = new BucketIds(channelId: channelId);
return await SendJsonAsync<Message>("POST", () => $"channels/{channelId}/messages", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}


/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception>
public async Task<Message> CreateWebhookMessageAsync(ulong webhookId, CreateWebhookMessageParams args, RequestOptions options = null)
public async Task<Message> CreateWebhookMessageAsync(ulong webhookId, CreateWebhookMessageParams args, RequestOptions options = null, ulong? threadId = null)
{
if (AuthTokenType != TokenType.Webhook)
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token.");
Expand All @@ -816,12 +820,12 @@ public async Task<Message> CreateWebhookMessageAsync(ulong webhookId, CreateWebh
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(webhookId: webhookId);
return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}

/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception>
public async Task ModifyWebhookMessageAsync(ulong webhookId, ulong messageId, ModifyWebhookMessageParams args, RequestOptions options = null)
public async Task ModifyWebhookMessageAsync(ulong webhookId, ulong messageId, ModifyWebhookMessageParams args, RequestOptions options = null, ulong? threadId = null)
{
if (AuthTokenType != TokenType.Webhook)
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token.");
Expand All @@ -837,11 +841,11 @@ public async Task ModifyWebhookMessageAsync(ulong webhookId, ulong messageId, Mo
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(webhookId: webhookId);
await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}${WebhookQuery(false, threadId)}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}

/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception>
public async Task DeleteWebhookMessageAsync(ulong webhookId, ulong messageId, RequestOptions options = null)
public async Task DeleteWebhookMessageAsync(ulong webhookId, ulong messageId, RequestOptions options = null, ulong? threadId = null)
{
if (AuthTokenType != TokenType.Webhook)
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token.");
Expand All @@ -852,7 +856,7 @@ public async Task DeleteWebhookMessageAsync(ulong webhookId, ulong messageId, Re
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(webhookId: webhookId);
await SendAsync("DELETE", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", ids, options: options).ConfigureAwait(false);
await SendAsync("DELETE", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}?{WebhookQuery(false, threadId)}", ids, options: options).ConfigureAwait(false);
}

/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
Expand All @@ -873,7 +877,7 @@ public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams arg

/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception>
public async Task<Message> UploadWebhookFileAsync(ulong webhookId, UploadWebhookFileParams args, RequestOptions options = null)
public async Task<Message> UploadWebhookFileAsync(ulong webhookId, UploadWebhookFileParams args, RequestOptions options = null, ulong? threadId = null)
{
if (AuthTokenType != TokenType.Webhook)
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token.");
Expand All @@ -893,7 +897,7 @@ public async Task<Message> UploadWebhookFileAsync(ulong webhookId, UploadWebhook
}

var ids = new BucketIds(webhookId: webhookId);
return await SendMultipartAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendMultipartAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}
public async Task DeleteMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
Expand Down Expand Up @@ -1380,7 +1384,7 @@ public async Task<Message> CreateInteractionFollowupMessageAsync(CreateWebhookMe
if ((!args.Embeds.IsSpecified || args.Embeds.Value == null || args.Embeds.Value.Length == 0) && !args.File.IsSpecified)
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));

if(args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));

options = RequestOptions.CreateOrClone(options);
Expand All @@ -1400,7 +1404,7 @@ public async Task<Message> CreateInteractionFollowupMessageAsync(UploadWebhookFi
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));

options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds();
return await SendMultipartAsync<Message>("POST", () => $"webhooks/{CurrentApplicationId}/{token}?wait=true", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}
Expand Down Expand Up @@ -1729,8 +1733,10 @@ public async Task<InviteMetadata> CreateChannelInviteAsync(ulong channelId, Crea
if (args.TargetType.IsSpecified)
{
Preconditions.NotEqual((int)args.TargetType.Value, (int)TargetUserType.Undefined, nameof(args.TargetType));
if (args.TargetType.Value == TargetUserType.Stream) Preconditions.GreaterThan(args.TargetUserId, 0, nameof(args.TargetUserId));
if (args.TargetType.Value == TargetUserType.EmbeddedApplication) Preconditions.GreaterThan(args.TargetApplicationId, 0, nameof(args.TargetUserId));
if (args.TargetType.Value == TargetUserType.Stream)
Preconditions.GreaterThan(args.TargetUserId, 0, nameof(args.TargetUserId));
if (args.TargetType.Value == TargetUserType.EmbeddedApplication)
Preconditions.GreaterThan(args.TargetApplicationId, 0, nameof(args.TargetUserId));
}
options = RequestOptions.CreateOrClone(options);

Expand Down Expand Up @@ -2414,6 +2420,18 @@ private static string GetFieldName(Expression expr)

return (expr as MemberExpression).Member.Name;
}

private static string WebhookQuery(bool wait = false, ulong? threadId = null)
{
List<string> querys = new List<string>() { };
if (wait)
querys.Add("wait=true");
if (threadId.HasValue)
querys.Add($"thread_id={threadId}");

return $"{string.Join("&", querys)}";
}

#endregion
}
}
28 changes: 14 additions & 14 deletions src/Discord.Net.Webhook/DiscordWebhookClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendMessageAsync(string text = null, bool isTTS = false, IEnumerable<Embed> embeds = null,
string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null,
MessageComponent components = null, MessageFlags flags = MessageFlags.None)
=> WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, components, flags);
MessageComponent components = null, MessageFlags flags = MessageFlags.None, ulong? threadId = null)
=> WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, components, flags, threadId);

/// <summary>
/// Modifies a message posted using this webhook.
Expand All @@ -103,8 +103,8 @@ private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
public Task ModifyMessageAsync(ulong messageId, Action<WebhookMessageProperties> func, RequestOptions options = null)
=> WebhookClientHelper.ModifyMessageAsync(this, messageId, func, options);
public Task ModifyMessageAsync(ulong messageId, Action<WebhookMessageProperties> func, RequestOptions options = null, ulong? threadId = null)
=> WebhookClientHelper.ModifyMessageAsync(this, messageId, func, options, threadId);

/// <summary>
/// Deletes a message posted using this webhook.
Expand All @@ -117,43 +117,43 @@ public Task ModifyMessageAsync(ulong messageId, Action<WebhookMessageProperties>
/// <returns>
/// A task that represents the asynchronous deletion operation.
/// </returns>
public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> WebhookClientHelper.DeleteMessageAsync(this, messageId, options);
public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null, ulong ? threadId = null)
=> WebhookClientHelper.DeleteMessageAsync(this, messageId, options, threadId);

/// <summary> Sends a message to the channel for this webhook with an attachment. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendFileAsync(string filePath, string text, bool isTTS = false,
IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null,
RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null,
MessageComponent components = null, MessageFlags flags = MessageFlags.None)
MessageComponent components = null, MessageFlags flags = MessageFlags.None, ulong? threadId = null)
=> WebhookClientHelper.SendFileAsync(this, filePath, text, isTTS, embeds, username, avatarUrl,
allowedMentions, options, isSpoiler, components, flags);
allowedMentions, options, isSpoiler, components, flags, threadId);
/// <summary> Sends a message to the channel for this webhook with an attachment. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false,
IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null,
RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null,
MessageComponent components = null, MessageFlags flags = MessageFlags.None)
MessageComponent components = null, MessageFlags flags = MessageFlags.None, ulong? threadId = null)
=> WebhookClientHelper.SendFileAsync(this, stream, filename, text, isTTS, embeds, username,
avatarUrl, allowedMentions, options, isSpoiler, components, flags);
avatarUrl, allowedMentions, options, isSpoiler, components, flags, threadId);

/// <summary> Sends a message to the channel for this webhook with an attachment. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false,
IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null,
RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null,
MessageFlags flags = MessageFlags.None)
MessageFlags flags = MessageFlags.None, ulong? threadId = null)
=> WebhookClientHelper.SendFileAsync(this, attachment, text, isTTS, embeds, username,
avatarUrl, allowedMentions, components, options, flags);
avatarUrl, allowedMentions, components, options, flags, threadId);

/// <summary> Sends a message to the channel for this webhook with an attachment. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false,
IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null,
RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null,
MessageFlags flags = MessageFlags.None)
MessageFlags flags = MessageFlags.None, ulong? threadId = null)
=> WebhookClientHelper.SendFilesAsync(this, attachments, text, isTTS, embeds, username, avatarUrl,
allowedMentions, components, options, flags);
allowedMentions, components, options, flags, threadId);


/// <summary> Modifies the properties of this webhook. </summary>
Expand Down
Loading

0 comments on commit b0a3b65

Please sign in to comment.