diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 91d533a596..8fe28cb075 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -28,10 +28,10 @@ namespace Discord.API internal class DiscordRestApiClient : IDisposable, IAsyncDisposable { #region DiscordRestApiClient - private static readonly ConcurrentDictionary> _bucketIdGenerators = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> _bucketIdGenerators = new (); public event Func SentRequest { add { _sentRequestEvent.Add(value); } remove { _sentRequestEvent.Remove(value); } } - private readonly AsyncEvent> _sentRequestEvent = new AsyncEvent>(); + private readonly AsyncEvent> _sentRequestEvent = new (); protected readonly JsonSerializer _serializer; protected readonly SemaphoreSlim _stateLock; @@ -136,6 +136,7 @@ public async Task LoginAsync(TokenType tokenType, string token, RequestOptions o } finally { _stateLock.Release(); } } + private async Task LoginInternalAsync(TokenType tokenType, string token, RequestOptions options = null) { if (LoginState != LoginState.LoggedOut) diff --git a/src/Discord.Net.Webhook/DiscordWebhookClient.cs b/src/Discord.Net.Webhook/DiscordWebhookClient.cs index 7243e5452c..125a369b71 100644 --- a/src/Discord.Net.Webhook/DiscordWebhookClient.cs +++ b/src/Discord.Net.Webhook/DiscordWebhookClient.cs @@ -13,7 +13,7 @@ namespace Discord.Webhook; /// /// A client responsible for connecting as a Webhook. /// -public class DiscordWebhookClient : IDisposable +public class DiscordWebhookClient : IAsyncDisposable, IDisposable { public event Func Log { @@ -21,74 +21,24 @@ public event Func Log remove => _logEvent.Remove(value); } - internal readonly AsyncEvent> _logEvent = new AsyncEvent>(); + internal readonly AsyncEvent> _logEvent = new(); - private readonly ulong _webhookId; - internal IWebhook Webhook; + internal ulong WebhookId; internal readonly Logger _restLogger; internal API.DiscordRestApiClient ApiClient { get; } internal LogManager LogManager { get; } - /// - /// Creates a new Webhook Discord client. - /// - public DiscordWebhookClient(IWebhook webhook) - : this(webhook.Id, webhook.Token, new DiscordRestConfig()) { } - - /// - /// Creates a new Webhook Discord client. - /// - public DiscordWebhookClient(ulong webhookId, string webhookToken) - : this(webhookId, webhookToken, new DiscordRestConfig()) { } - - /// - /// Creates a new Webhook Discord client. - /// - public DiscordWebhookClient(string webhookUrl) - : this(webhookUrl, new DiscordRestConfig()) { } - // regex pattern to match webhook urls - private static Regex WebhookUrlRegex = new Regex(@"^.*(discord|discordapp)\.com\/api\/webhooks\/([\d]+)\/([a-z0-9_-]+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + private static Regex WebhookUrlRegex = new(@"^.*(discord|discordapp)\.com\/api\/webhooks\/([\d]+)\/([a-z0-9_-]+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); /// /// Creates a new Webhook Discord client. /// - public DiscordWebhookClient(ulong webhookId, string webhookToken, DiscordRestConfig config) - : this(config) + public DiscordWebhookClient(DiscordRestConfig config = null) { - _webhookId = webhookId; - ApiClient.LoginAsync(TokenType.Webhook, webhookToken).GetAwaiter().GetResult(); - Webhook = WebhookClientHelper.GetWebhookAsync(this, webhookId).GetAwaiter().GetResult(); - } - - /// - /// Creates a new Webhook Discord client. - /// - public DiscordWebhookClient(IWebhook webhook, DiscordRestConfig config) - : this(config) - { - Webhook = webhook; - _webhookId = Webhook.Id; - ApiClient.LoginAsync(TokenType.Webhook, webhook.Token).GetAwaiter().GetResult(); - } - - /// - /// Creates a new Webhook Discord client. - /// - /// The url of the webhook. - /// The configuration options to use for this client. - /// Thrown if the is an invalid format. - /// Thrown if the is null or whitespace. - public DiscordWebhookClient(string webhookUrl, DiscordRestConfig config) : this(config) - { - ParseWebhookUrl(webhookUrl, out _webhookId, out string token); - ApiClient.LoginAsync(TokenType.Webhook, token).GetAwaiter().GetResult(); - Webhook = WebhookClientHelper.GetWebhookAsync(this, _webhookId).GetAwaiter().GetResult(); - } + config ??= new DiscordRestConfig(); - private DiscordWebhookClient(DiscordRestConfig config) - { ApiClient = CreateApiClient(config); LogManager = new LogManager(config.LogLevel); LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false); @@ -104,9 +54,30 @@ private DiscordWebhookClient(DiscordRestConfig config) }; ApiClient.SentRequest += async (method, endpoint, millis) => await _restLogger.VerboseAsync($"{method} {endpoint}: {millis} ms").ConfigureAwait(false); } + + public async Task LoginAsync(ulong webhookId, string webhookToken) + { + WebhookId = webhookId; + + await ApiClient.LoginAsync(TokenType.Webhook, webhookToken).ConfigureAwait(false); + } + + public async Task LoginAsync(IWebhook webhook) + { + WebhookId = webhook.Id; + + await ApiClient.LoginAsync(TokenType.Webhook, webhook.Token).ConfigureAwait(false); + } + + public async Task LoginAsync(string webhookUrl) + { + ParseWebhookUrl(webhookUrl, out WebhookId, out var webhookToken); + await ApiClient.LoginAsync(TokenType.Webhook, webhookToken).ConfigureAwait(false); + } + private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config) - => new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, useSystemClock: config.UseSystemClock, defaultRatelimitCallback: config.DefaultRatelimitCallback); - + => new(config.RestClientProvider, DiscordConfig.UserAgent, useSystemClock: config.UseSystemClock, defaultRatelimitCallback: config.DefaultRatelimitCallback); + /// /// Sends a message to the channel for this webhook. /// @@ -161,7 +132,7 @@ public Task SendFileAsync(string filePath, string text, bool isTTS = fals string threadName = null, ulong[] appliedTags = null, PollProperties poll = null) => WebhookClientHelper.SendFileAsync(this, filePath, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, isSpoiler, components, flags, threadId, threadName, appliedTags, poll); - + /// /// Sends a message to the channel for this webhook with an attachment. /// @@ -202,21 +173,13 @@ public Task SendFilesAsync(IEnumerable attachments, strin /// Modifies the properties of this webhook. /// public Task ModifyWebhookAsync(Action func, RequestOptions options = null) - => Webhook.ModifyAsync(func, options); + => WebhookClientHelper.ModifyAsync(this, func, options); /// /// Deletes this webhook from Discord and disposes the client. /// - public async Task DeleteWebhookAsync(RequestOptions options = null) - { - await Webhook.DeleteAsync(options).ConfigureAwait(false); - Dispose(); - } - - public void Dispose() - { - ApiClient?.Dispose(); - } + public Task DeleteWebhookAsync(RequestOptions options = null) + => WebhookClientHelper.DeleteAsync(this, options); internal static void ParseWebhookUrl(string webhookUrl, out ulong webhookId, out string webhookToken) { @@ -225,7 +188,7 @@ internal static void ParseWebhookUrl(string webhookUrl, out ulong webhookId, out // thrown when groups are not populated/valid, or when there is no match ArgumentException ex(string reason = null) - => new ($"The given webhook Url was not in a valid format. {reason}", nameof(webhookUrl)); + => new($"The given webhook Url was not in a valid format. {reason}", nameof(webhookUrl)); var match = WebhookUrlRegex.Match(webhookUrl); @@ -243,4 +206,12 @@ ArgumentException ex(string reason = null) else throw ex(); } + + public async ValueTask DisposeAsync() + { + if (ApiClient != null) + await ApiClient.DisposeAsync(); + } + + public void Dispose() => ApiClient?.Dispose(); } diff --git a/src/Discord.Net.Webhook/WebhookClientHelper.cs b/src/Discord.Net.Webhook/WebhookClientHelper.cs index 47db9a21bb..45ea81d1c9 100644 --- a/src/Discord.Net.Webhook/WebhookClientHelper.cs +++ b/src/Discord.Net.Webhook/WebhookClientHelper.cs @@ -59,7 +59,7 @@ public static async Task SendMessageAsync(DiscordWebhookClient client, if (flags is not MessageFlags.None and not MessageFlags.SuppressEmbeds and not MessageFlags.SuppressNotification) throw new ArgumentException("The only valid MessageFlags are SuppressEmbeds, SuppressNotification and none.", nameof(flags)); - var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options, threadId: threadId).ConfigureAwait(false); + var model = await client.ApiClient.CreateWebhookMessageAsync(client.WebhookId, args, options: options, threadId: threadId).ConfigureAwait(false); return model.Id; } @@ -111,7 +111,7 @@ public static Task ModifyMessageAsync(DiscordWebhookClient client, ulong message Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, }; - return client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options, threadId); + return client.ApiClient.ModifyWebhookMessageAsync(client.WebhookId, messageId, apiArgs, options, threadId); } else { @@ -130,12 +130,12 @@ public static Task ModifyMessageAsync(DiscordWebhookClient client, ulong message MessageComponents = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, }; - return client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options, threadId); + return client.ApiClient.ModifyWebhookMessageAsync(client.WebhookId, messageId, apiArgs, options, threadId); } } public static Task DeleteMessageAsync(DiscordWebhookClient client, ulong messageId, RequestOptions options, ulong? threadId) - => client.ApiClient.DeleteWebhookMessageAsync(client.Webhook.Id, messageId, options, threadId); + => client.ApiClient.DeleteWebhookMessageAsync(client.WebhookId, messageId, options, threadId); public static async Task SendFileAsync(DiscordWebhookClient client, string filePath, string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, @@ -210,7 +210,7 @@ public static async Task SendFilesAsync(DiscordWebhookClient client, AppliedTags = appliedTags, Poll = poll?.ToModel() ?? Optional.Unspecified }; - var msg = await client.ApiClient.UploadWebhookFileAsync(client.Webhook.Id, args, options, threadId).ConfigureAwait(false); + var msg = await client.ApiClient.UploadWebhookFileAsync(client.WebhookId, args, options, threadId).ConfigureAwait(false); return msg.Id; } @@ -224,13 +224,10 @@ public static Task ModifyAsync(DiscordWebhookClient client, Action Name = args.Name }; - if (!apiArgs.Avatar.IsSpecified && client.Webhook.AvatarId != null) - apiArgs.Avatar = new ImageModel(client.Webhook.AvatarId); - - return client.ApiClient.ModifyWebhookAsync(client.Webhook.Id, apiArgs, options); + return client.ApiClient.ModifyWebhookAsync(client.WebhookId, apiArgs, options); } public static Task DeleteAsync(DiscordWebhookClient client, RequestOptions options) - => client.ApiClient.DeleteWebhookAsync(client.Webhook.Id, options); + => client.ApiClient.DeleteWebhookAsync(client.WebhookId, options); } }