From 4c17ee3d89ab223ad1203c3d0c5682cfca7183f9 Mon Sep 17 00:00:00 2001 From: Ske Date: Sun, 8 Aug 2021 21:56:24 +0200 Subject: [PATCH] Fix proxying in channels without message history + reduce proxy latency --- PluralKit.Bot/Commands/MessageEdit.cs | 2 ++ PluralKit.Bot/Handlers/MessageCreated.cs | 2 +- PluralKit.Bot/Handlers/MessageEdited.cs | 2 +- PluralKit.Bot/Proxy/ProxyService.cs | 28 ++++++--------- .../Services/LastMessageCacheService.cs | 35 +++++++++++-------- .../Repository/ModelRepository.Message.cs | 2 +- 6 files changed, 35 insertions(+), 36 deletions(-) diff --git a/PluralKit.Bot/Commands/MessageEdit.cs b/PluralKit.Bot/Commands/MessageEdit.cs index 298021c8..028ad6ff 100644 --- a/PluralKit.Bot/Commands/MessageEdit.cs +++ b/PluralKit.Bot/Commands/MessageEdit.cs @@ -95,6 +95,8 @@ namespace PluralKit.Bot throw new PKError("Could not find a recent message to edit."); msg = await _repo.GetMessage(conn, recent.Mid); + if (msg == null) + throw new PKError("Could not find a recent message to edit."); } return msg; diff --git a/PluralKit.Bot/Handlers/MessageCreated.cs b/PluralKit.Bot/Handlers/MessageCreated.cs index d13bbd78..82da5d03 100644 --- a/PluralKit.Bot/Handlers/MessageCreated.cs +++ b/PluralKit.Bot/Handlers/MessageCreated.cs @@ -53,7 +53,7 @@ namespace PluralKit.Bot private bool IsDuplicateMessage(Message msg) => // We consider a message duplicate if it has the same ID as the previous message that hit the gateway - _lastMessageCache.GetLastMessage(msg.ChannelId)?.Id == msg.Id; + _lastMessageCache.GetLastMessage(msg.ChannelId)?.Current.Id == msg.Id; public async Task Handle(Shard shard, MessageCreateEvent evt) { diff --git a/PluralKit.Bot/Handlers/MessageEdited.cs b/PluralKit.Bot/Handlers/MessageEdited.cs index e1afe47d..cb38032b 100644 --- a/PluralKit.Bot/Handlers/MessageEdited.cs +++ b/PluralKit.Bot/Handlers/MessageEdited.cs @@ -55,7 +55,7 @@ namespace PluralKit.Bot if (!DiscordUtils.IsValidGuildChannel(channel)) return; var guild = _cache.GetGuild(channel.GuildId!.Value); - var lastMessage = _lastMessageCache.GetLastMessage(evt.ChannelId); + var lastMessage = _lastMessageCache.GetLastMessage(evt.ChannelId)?.Current; // Only react to the last message in the channel if (lastMessage?.Id != evt.Id) diff --git a/PluralKit.Bot/Proxy/ProxyService.cs b/PluralKit.Bot/Proxy/ProxyService.cs index b9a570ef..8ac0d124 100644 --- a/PluralKit.Bot/Proxy/ProxyService.cs +++ b/PluralKit.Bot/Proxy/ProxyService.cs @@ -242,40 +242,32 @@ namespace PluralKit.Bot }; } - private async Task FixSameName(ulong channel_id, MessageContext ctx, ProxyMember member) + private async Task FixSameName(ulong channelId, MessageContext ctx, ProxyMember member) { var proxyName = member.ProxyName(ctx); - - Message? lastMessage = null; - - var lastMessageId = _lastMessage.GetLastMessage(channel_id)?.Previous; - if (lastMessageId == null) + + var lastMessage = _lastMessage.GetLastMessage(channelId)?.Previous; + if (lastMessage == null) // cache is out of date or channel is empty. return proxyName; - - lastMessage = await _rest.GetMessage(channel_id, lastMessageId.Value); - - if (lastMessage == null) - // we don't have enough information to figure out if we need to fix the name, so bail here. - return proxyName; - + await using var conn = await _db.Obtain(); - var message = await _repo.GetMessage(conn, lastMessage.Id); + var pkMessage = await _repo.GetMessage(conn, lastMessage.Id); - if (lastMessage.Author.Username == proxyName) + if (lastMessage.AuthorUsername == proxyName) { // last message wasn't proxied by us, but somehow has the same name // it's probably from a different webhook (Tupperbox?) but let's fix it anyway! - if (message == null) + if (pkMessage == null) return FixSameNameInner(proxyName); // last message was proxied by a different member - if (message.Member.Id != member.Id) + if (pkMessage.Member.Id != member.Id) return FixSameNameInner(proxyName); } // if we fixed the name last message and it's the same member proxying, we want to fix it again - if (lastMessage.Author.Username == FixSameNameInner(proxyName) && message?.Member.Id == member.Id) + if (lastMessage.AuthorUsername == FixSameNameInner(proxyName) && pkMessage?.Member.Id == member.Id) return FixSameNameInner(proxyName); // No issues found, current proxy name is fine. diff --git a/PluralKit.Bot/Services/LastMessageCacheService.cs b/PluralKit.Bot/Services/LastMessageCacheService.cs index f13d34e5..b5ec3ca4 100644 --- a/PluralKit.Bot/Services/LastMessageCacheService.cs +++ b/PluralKit.Bot/Services/LastMessageCacheService.cs @@ -1,7 +1,6 @@ #nullable enable using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using Myriad.Types; @@ -10,15 +9,19 @@ namespace PluralKit.Bot // TODO: Should this be moved to Myriad.Cache? public class LastMessageCacheService { - private readonly IDictionary _cache = new ConcurrentDictionary(); + private readonly IDictionary _cache = new ConcurrentDictionary(); public void AddMessage(Message msg) { var previous = GetLastMessage(msg.ChannelId); - _cache[msg.ChannelId] = new CachedMessage(msg.Id, msg.ReferencedMessage.Value?.Id, previous?.Id); + var current = ToCachedMessage(msg); + _cache[msg.ChannelId] = new(current, previous?.Current); } - public CachedMessage? GetLastMessage(ulong channel) + private CachedMessage ToCachedMessage(Message msg) => + new(msg.Id, msg.ReferencedMessage.Value?.Id, msg.Author.Username); + + public CacheEntry? GetLastMessage(ulong channel) { return _cache.TryGetValue(channel, out var message) ? message : null; } @@ -29,13 +32,13 @@ namespace PluralKit.Bot if (storedMessage == null) return; - if (message == storedMessage.Id) + if (message == storedMessage.Current.Id) if (storedMessage.Previous != null) - _cache[channel] = new CachedMessage(storedMessage.Previous.Value, null, null); + _cache[channel] = new(storedMessage.Previous, null); else _cache.Remove(channel); - else if (message == storedMessage.Previous) - _cache[channel] = new CachedMessage(storedMessage.Id, storedMessage.ReferencedMessage, null); + else if (message == storedMessage.Previous?.Id) + _cache[channel] = new(storedMessage.Current, null); } public void HandleMessageDeletion(ulong channel, List messages) @@ -44,21 +47,21 @@ namespace PluralKit.Bot if (storedMessage == null) return; - if (!(messages.Contains(storedMessage.Id) || (storedMessage.Previous != null && messages.Contains(storedMessage.Previous.Value)))) + if (!(messages.Contains(storedMessage.Current.Id) || storedMessage.Previous != null && messages.Contains(storedMessage.Previous.Id))) // none of the deleted messages are relevant to the cache return; ulong? newLastMessage = null; - if (messages.Contains(storedMessage.Id)) - newLastMessage = storedMessage.Previous; + if (messages.Contains(storedMessage.Current.Id)) + newLastMessage = storedMessage.Previous?.Id; - if (storedMessage.Previous != null && messages.Contains(storedMessage.Previous.Value)) - if (newLastMessage == storedMessage.Previous) + if (storedMessage.Previous != null && messages.Contains(storedMessage.Previous.Id)) + if (newLastMessage == storedMessage.Previous?.Id) newLastMessage = null; else { - _cache[channel] = new CachedMessage(storedMessage.Id, storedMessage.ReferencedMessage, null); + _cache[channel] = new(storedMessage.Current, null); return; } @@ -67,5 +70,7 @@ namespace PluralKit.Bot } } - public record CachedMessage(ulong Id, ulong? ReferencedMessage, ulong? Previous); + public record CacheEntry(CachedMessage Current, CachedMessage? Previous); + + public record CachedMessage(ulong Id, ulong? ReferencedMessage, string AuthorUsername); } diff --git a/PluralKit.Core/Database/Repository/ModelRepository.Message.cs b/PluralKit.Core/Database/Repository/ModelRepository.Message.cs index 2622ef38..4e64bab5 100644 --- a/PluralKit.Core/Database/Repository/ModelRepository.Message.cs +++ b/PluralKit.Core/Database/Repository/ModelRepository.Message.cs @@ -14,7 +14,7 @@ namespace PluralKit.Core _logger.Debug("Stored message {@StoredMessage} in channel {Channel}", msg, msg.Channel); } - public async Task GetMessage(IPKConnection conn, ulong id) + public async Task GetMessage(IPKConnection conn, ulong id) { FullMessage Mapper(PKMessage msg, PKMember member, PKSystem system) => new FullMessage {Message = msg, System = system, Member = member};