Delete proxied message if the trigger message gets deleted by other means

This commit is contained in:
Ske 2020-11-15 14:34:49 +01:00
parent 8c12b3f037
commit 27c9e54f17
2 changed files with 47 additions and 23 deletions

View File

@ -96,45 +96,69 @@ namespace PluralKit.Bot
// Send the webhook // Send the webhook
var content = match.ProxyContent; var content = match.ProxyContent;
if (!allowEmbeds) content = content.BreakLinkEmbeds(); if (!allowEmbeds) content = content.BreakLinkEmbeds();
var id = await _webhookExecutor.ExecuteWebhook(trigger.Channel, match.Member.ProxyName(ctx), var proxyMessage = await _webhookExecutor.ExecuteWebhook(trigger.Channel, match.Member.ProxyName(ctx),
match.Member.ProxyAvatar(ctx), match.Member.ProxyAvatar(ctx),
content, trigger.Attachments, allowEveryone); content, trigger.Attachments, allowEveryone);
Task SaveMessage() => _repo.AddMessage(conn, new PKMessage await HandleProxyExecutedActions(conn, ctx, trigger, proxyMessage, match);
}
private async Task HandleProxyExecutedActions(IPKConnection conn, MessageContext ctx,
DiscordMessage triggerMessage, DiscordMessage proxyMessage,
ProxyMatch match)
{ {
Channel = trigger.ChannelId, Task SaveMessageInDatabase() => _repo.AddMessage(conn, new PKMessage
Guild = trigger.Channel.GuildId, {
Channel = triggerMessage.ChannelId,
Guild = triggerMessage.Channel.GuildId,
Member = match.Member.Id, Member = match.Member.Id,
Mid = id, Mid = proxyMessage.Id,
OriginalMid = trigger.Id, OriginalMid = triggerMessage.Id,
Sender = trigger.Author.Id Sender = triggerMessage.Author.Id
}); });
Task LogMessage() => _logChannel.LogMessage(ctx, match, trigger, id).AsTask(); Task LogMessageToChannel() => _logChannel.LogMessage(ctx, match, triggerMessage, proxyMessage.Id).AsTask();
async Task DeleteMessage()
async Task DeleteProxyTriggerMessage()
{ {
// Wait a second or so before deleting the original message // Wait a second or so before deleting the original message
await Task.Delay(MessageDeletionDelay); await Task.Delay(MessageDeletionDelay);
try try
{ {
await trigger.DeleteAsync(); await triggerMessage.DeleteAsync();
} }
catch (NotFoundException) catch (NotFoundException)
{ {
// If it's already deleted, we just log and swallow the exception _logger.Debug("Trigger message {TriggerMessageId} was already deleted when we attempted to; deleting proxy message {ProxyMessageId} also",
_logger.Warning("Attempted to delete already deleted proxy trigger message {Message}", trigger.Id); triggerMessage.Id, proxyMessage.Id);
await HandleTriggerAlreadyDeleted(proxyMessage);
// Swallow the exception, we don't need it
} }
} }
// Run post-proxy actions (simultaneously; order doesn't matter) // Run post-proxy actions (simultaneously; order doesn't matter)
// Note that only AddMessage is using our passed-in connection, careful not to pass it elsewhere and run into conflicts // Note that only AddMessage is using our passed-in connection, careful not to pass it elsewhere and run into conflicts
await Task.WhenAll( await Task.WhenAll(
DeleteMessage(), DeleteProxyTriggerMessage(),
SaveMessage(), SaveMessageInDatabase(),
LogMessage() LogMessageToChannel()
); );
} }
private async Task HandleTriggerAlreadyDeleted(DiscordMessage proxyMessage)
{
// If a trigger message is deleted before we get to delete it, we can assume a mod bot or similar got to it
// In this case we should also delete the now-proxied message.
// This is going to hit the message delete event handler also, so that'll do the cleanup for us
try
{
await proxyMessage.DeleteAsync();
}
catch (NotFoundException) { }
catch (UnauthorizedException) { }
}
private async Task<bool> CheckBotPermissionsOrError(DiscordChannel channel) private async Task<bool> CheckBotPermissionsOrError(DiscordChannel channel)
{ {
var permissions = channel.BotPermissions(); var permissions = channel.BotPermissions();

View File

@ -42,23 +42,23 @@ namespace PluralKit.Bot
_logger = logger.ForContext<WebhookExecutorService>(); _logger = logger.ForContext<WebhookExecutorService>();
} }
public async Task<ulong> ExecuteWebhook(DiscordChannel channel, string name, string avatarUrl, string content, IReadOnlyList<DiscordAttachment> attachments, bool allowEveryone) public async Task<DiscordMessage> ExecuteWebhook(DiscordChannel channel, string name, string avatarUrl, string content, IReadOnlyList<DiscordAttachment> attachments, bool allowEveryone)
{ {
_logger.Verbose("Invoking webhook in channel {Channel}", channel.Id); _logger.Verbose("Invoking webhook in channel {Channel}", channel.Id);
// Get a webhook, execute it // Get a webhook, execute it
var webhook = await _webhookCache.GetWebhook(channel); var webhook = await _webhookCache.GetWebhook(channel);
var id = await ExecuteWebhookInner(channel, webhook, name, avatarUrl, content, attachments, allowEveryone); var webhookMessage = await ExecuteWebhookInner(channel, webhook, name, avatarUrl, content, attachments, allowEveryone);
// Log the relevant metrics // Log the relevant metrics
_metrics.Measure.Meter.Mark(BotMetrics.MessagesProxied); _metrics.Measure.Meter.Mark(BotMetrics.MessagesProxied);
_logger.Information("Invoked webhook {Webhook} in channel {Channel}", webhook.Id, _logger.Information("Invoked webhook {Webhook} in channel {Channel}", webhook.Id,
channel.Id); channel.Id);
return id; return webhookMessage;
} }
private async Task<ulong> ExecuteWebhookInner(DiscordChannel channel, DiscordWebhook webhook, string name, string avatarUrl, string content, private async Task<DiscordMessage> ExecuteWebhookInner(DiscordChannel channel, DiscordWebhook webhook, string name, string avatarUrl, string content,
IReadOnlyList<DiscordAttachment> attachments, bool allowEveryone, bool hasRetried = false) IReadOnlyList<DiscordAttachment> attachments, bool allowEveryone, bool hasRetried = false)
{ {
content = content.Truncate(2000); content = content.Truncate(2000);
@ -77,11 +77,11 @@ namespace PluralKit.Bot
await AddAttachmentsToBuilder(dwb, attachmentChunks[0]); await AddAttachmentsToBuilder(dwb, attachmentChunks[0]);
} }
DiscordMessage response; DiscordMessage webhookMessage;
using (_metrics.Measure.Timer.Time(BotMetrics.WebhookResponseTime)) { using (_metrics.Measure.Timer.Time(BotMetrics.WebhookResponseTime)) {
try try
{ {
response = await webhook.ExecuteAsync(dwb); webhookMessage = await webhook.ExecuteAsync(dwb);
} }
catch (JsonReaderException) catch (JsonReaderException)
{ {
@ -109,7 +109,7 @@ namespace PluralKit.Bot
// We don't care about whether the sending succeeds, and we don't want to *wait* for it, so we just fork it off // We don't care about whether the sending succeeds, and we don't want to *wait* for it, so we just fork it off
var _ = TrySendRemainingAttachments(webhook, name, avatarUrl, attachmentChunks); var _ = TrySendRemainingAttachments(webhook, name, avatarUrl, attachmentChunks);
return response.Id; return webhookMessage;
} }
private async Task TrySendRemainingAttachments(DiscordWebhook webhook, string name, string avatarUrl, IReadOnlyList<IReadOnlyCollection<DiscordAttachment>> attachmentChunks) private async Task TrySendRemainingAttachments(DiscordWebhook webhook, string name, string avatarUrl, IReadOnlyList<IReadOnlyCollection<DiscordAttachment>> attachmentChunks)