fix: remove unnecessary async methods, fix PluralkitApiService

This commit is contained in:
sam 2024-09-02 15:59:16 +02:00
parent 086eb95452
commit db01f879bd
Signed by: sam
GPG key ID: 5F3C3C1B3166639D
10 changed files with 96 additions and 73 deletions

View file

@ -11,7 +11,6 @@ using Guild = Catalogger.Backend.Database.Models.Guild;
namespace Catalogger.Backend.Services;
// TODO: this entire class is a mess, clean it up
public class WebhookExecutorService(
Config config,
ILogger logger,
@ -28,14 +27,79 @@ public class WebhookExecutorService(
public void SetSelfUser(IUser user) => _selfUser = user;
public async Task QueueLogAsync(Guild guild, LogChannelType logChannelType, IEmbed embed)
/// <summary>
/// Queues a log embed for the given log channel type.
/// If the log channel is already known, use the ulong overload of this method instead.
/// If the log channel depends on the source channel and source user, also use the ulong overload.
/// </summary>
public void QueueLog(Guild guildConfig, LogChannelType logChannelType, IEmbed embed)
{
var logChannel = GetLogChannel(guild, logChannelType, channelId: null, userId: null);
var logChannel = GetLogChannel(guildConfig, logChannelType, channelId: null, userId: null);
if (logChannel == null) return;
await QueueLogAsync(logChannel.Value, embed);
QueueLog(logChannel.Value, embed);
}
/// <summary>
/// Queues a log embed for the given channel ID.
/// </summary>
public void QueueLog(ulong channelId, IEmbed embed)
{
if (channelId == 0) return;
var queue = _cache.GetOrAdd(channelId, []);
queue.Enqueue(embed);
_cache[channelId] = queue;
SetTimer(channelId, queue);
}
/// <summary>
/// Sends multiple embeds and/or files to a channel, bypassing the embed queue.
/// </summary>
/// <param name="channelId">The channel ID to send the content to.</param>
/// <param name="embeds">The embeds to send. Must be under 6000 characters in length total, this is not checked by this method.</param>
/// <param name="files">The files to send.</param>
public async Task SendLogAsync(ulong channelId, List<IEmbed> embeds, IEnumerable<FileData> files)
{
if (channelId == 0) return;
var attachments = files
.Select<FileData, OneOf.OneOf<FileData, IPartialAttachment>>(f => f)
.ToList();
_logger.Debug("Sending {EmbedCount} embeds/{FileCount} files to channel {ChannelId}", embeds.Count,
attachments.Count, channelId);
var webhook = await webhookCache.GetOrFetchWebhookAsync(channelId, id => FetchWebhookAsync(id));
await webhookApi.ExecuteWebhookAsync(DiscordSnowflake.New(webhook.Id), webhook.Token, shouldWait: false,
embeds: embeds, attachments: attachments, username: _selfUser!.Username,
avatarUrl: _selfUser.AvatarUrl());
}
/// <summary>
/// Sets a 3 second timer for the given channel.
/// </summary>
private void SetTimer(ulong channelId, ConcurrentQueue<IEmbed> queue)
{
if (_timers.TryGetValue(channelId, out var existingTimer)) existingTimer.Dispose();
_timers[channelId] = new Timer(_ =>
{
_logger.Debug("Sending 5 queued embeds");
var __ = SendLogAsync(channelId, TakeFromQueue(channelId).ToList(), []);
if (!queue.IsEmpty)
{
if (_timers.TryGetValue(channelId, out var timer)) timer.Dispose();
SetTimer(channelId, queue);
}
}, null, 3000, Timeout.Infinite);
}
/// <summary>
/// Takes 5 embeds from the queue for the given channel.
/// Note that this locks the queue to prevent duplicate embeds from being sent.
/// </summary>
private List<IEmbed> TakeFromQueue(ulong channelId)
{
var queue = _cache.GetOrAdd(channelId, []);
@ -53,58 +117,7 @@ public class WebhookExecutorService(
}
}
public async Task QueueLogAsync(ulong channelId, IEmbed embed)
{
if (channelId == 0) return;
var queue = _cache.GetOrAdd(channelId, []);
queue.Enqueue(embed);
_cache[channelId] = queue;
await SetTimer(channelId, queue);
}
private async Task SetTimer(ulong channelId, ConcurrentQueue<IEmbed> queue)
{
if (_timers.TryGetValue(channelId, out var existingTimer)) await existingTimer.DisposeAsync();
_timers[channelId] = new Timer(_ =>
{
_logger.Debug("Sending 5 queued embeds");
var __ = SendLogsAsync(channelId, TakeFromQueue(channelId));
if (!queue.IsEmpty)
{
if (_timers.TryGetValue(channelId, out var timer)) timer.Dispose();
var ___ = SetTimer(channelId, queue);
}
}, null, 3000, Timeout.Infinite);
}
private async Task SendLogsAsync(ulong channelId, List<IEmbed> embeds)
{
_logger.Debug("Sending {Count} embeds to channel {ChannelId}", embeds.Count, channelId);
if (embeds.Count == 0) return;
var webhook = await webhookCache.GetOrFetchWebhookAsync(channelId, id => FetchWebhookAsync(id));
await webhookApi.ExecuteWebhookAsync(DiscordSnowflake.New(webhook.Id), webhook.Token, shouldWait: false,
embeds: embeds, username: _selfUser!.Username, avatarUrl: _selfUser.AvatarUrl());
}
public async Task SendLogWithAttachmentsAsync(ulong channelId, List<Embed> embeds, IEnumerable<FileData> files)
{
if (channelId == 0) return;
var attachments = files
.Select<FileData, OneOf.OneOf<FileData, IPartialAttachment>>(f => f)
.ToList();
var webhook = await webhookCache.GetOrFetchWebhookAsync(channelId, id => FetchWebhookAsync(id));
await webhookApi.ExecuteWebhookAsync(DiscordSnowflake.New(webhook.Id), webhook.Token, shouldWait: false,
embeds: embeds, attachments: attachments, username: _selfUser!.Username,
avatarUrl: _selfUser.AvatarUrl());
}
// TODO: make it so this method can only have one request per channel in flight simultaneously
private async Task<IWebhook> FetchWebhookAsync(Snowflake channelId, CancellationToken ct = default)
{
var channelWebhooks =