using System; using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; using Discord; using Discord.WebSocket; namespace PluralKit.Bot { public class WebhookCacheService { public static readonly string WebhookName = "PluralKit Proxy Webhook"; private IDiscordClient _client; private ConcurrentDictionary>> _webhooks; public WebhookCacheService(IDiscordClient client) { this._client = client; _webhooks = new ConcurrentDictionary>>(); } public async Task GetWebhook(ulong channelId) { var channel = await _client.GetChannelAsync(channelId) as ITextChannel; if (channel == null) return null; return await GetWebhook(channel); } public async Task GetWebhook(ITextChannel channel) { // We cache the webhook through a Lazy>, this way we make sure to only create one webhook per channel // If the webhook is requested twice before it's actually been found, the Lazy wrapper will stop the // webhook from being created twice. var lazyWebhookValue = _webhooks.GetOrAdd(channel.Id, new Lazy>(() => GetOrCreateWebhook(channel))); return await lazyWebhookValue.Value; } private async Task GetOrCreateWebhook(ITextChannel channel) => await FindExistingWebhook(channel) ?? await GetOrCreateWebhook(channel); private async Task FindExistingWebhook(ITextChannel channel) => (await channel.GetWebhooksAsync()).FirstOrDefault(IsWebhookMine); private async Task DoCreateWebhook(ITextChannel channel) => await channel.CreateWebhookAsync(WebhookName); private bool IsWebhookMine(IWebhook arg) => arg.Creator.Id == _client.CurrentUser.Id && arg.Name == WebhookName; } }