Fix proxying in channels without message history + reduce proxy latency

This commit is contained in:
Ske 2021-08-08 21:56:24 +02:00
parent 1720a28af2
commit 4c17ee3d89
6 changed files with 35 additions and 36 deletions

View File

@ -95,6 +95,8 @@ namespace PluralKit.Bot
throw new PKError("Could not find a recent message to edit."); throw new PKError("Could not find a recent message to edit.");
msg = await _repo.GetMessage(conn, recent.Mid); msg = await _repo.GetMessage(conn, recent.Mid);
if (msg == null)
throw new PKError("Could not find a recent message to edit.");
} }
return msg; return msg;

View File

@ -53,7 +53,7 @@ namespace PluralKit.Bot
private bool IsDuplicateMessage(Message msg) => private bool IsDuplicateMessage(Message msg) =>
// We consider a message duplicate if it has the same ID as the previous message that hit the gateway // 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) public async Task Handle(Shard shard, MessageCreateEvent evt)
{ {

View File

@ -55,7 +55,7 @@ namespace PluralKit.Bot
if (!DiscordUtils.IsValidGuildChannel(channel)) if (!DiscordUtils.IsValidGuildChannel(channel))
return; return;
var guild = _cache.GetGuild(channel.GuildId!.Value); 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 // Only react to the last message in the channel
if (lastMessage?.Id != evt.Id) if (lastMessage?.Id != evt.Id)

View File

@ -242,40 +242,32 @@ namespace PluralKit.Bot
}; };
} }
private async Task<string> FixSameName(ulong channel_id, MessageContext ctx, ProxyMember member) private async Task<string> FixSameName(ulong channelId, MessageContext ctx, ProxyMember member)
{ {
var proxyName = member.ProxyName(ctx); var proxyName = member.ProxyName(ctx);
Message? lastMessage = null; var lastMessage = _lastMessage.GetLastMessage(channelId)?.Previous;
if (lastMessage == null)
var lastMessageId = _lastMessage.GetLastMessage(channel_id)?.Previous;
if (lastMessageId == null)
// cache is out of date or channel is empty. // cache is out of date or channel is empty.
return proxyName; 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(); 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 // 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! // it's probably from a different webhook (Tupperbox?) but let's fix it anyway!
if (message == null) if (pkMessage == null)
return FixSameNameInner(proxyName); return FixSameNameInner(proxyName);
// last message was proxied by a different member // last message was proxied by a different member
if (message.Member.Id != member.Id) if (pkMessage.Member.Id != member.Id)
return FixSameNameInner(proxyName); return FixSameNameInner(proxyName);
} }
// if we fixed the name last message and it's the same member proxying, we want to fix it again // 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); return FixSameNameInner(proxyName);
// No issues found, current proxy name is fine. // No issues found, current proxy name is fine.

View File

@ -1,7 +1,6 @@
#nullable enable #nullable enable
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Myriad.Types; using Myriad.Types;
@ -10,15 +9,19 @@ namespace PluralKit.Bot
// TODO: Should this be moved to Myriad.Cache? // TODO: Should this be moved to Myriad.Cache?
public class LastMessageCacheService public class LastMessageCacheService
{ {
private readonly IDictionary<ulong, CachedMessage> _cache = new ConcurrentDictionary<ulong, CachedMessage>(); private readonly IDictionary<ulong, CacheEntry> _cache = new ConcurrentDictionary<ulong, CacheEntry>();
public void AddMessage(Message msg) public void AddMessage(Message msg)
{ {
var previous = GetLastMessage(msg.ChannelId); 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; return _cache.TryGetValue(channel, out var message) ? message : null;
} }
@ -29,13 +32,13 @@ namespace PluralKit.Bot
if (storedMessage == null) if (storedMessage == null)
return; return;
if (message == storedMessage.Id) if (message == storedMessage.Current.Id)
if (storedMessage.Previous != null) if (storedMessage.Previous != null)
_cache[channel] = new CachedMessage(storedMessage.Previous.Value, null, null); _cache[channel] = new(storedMessage.Previous, null);
else else
_cache.Remove(channel); _cache.Remove(channel);
else if (message == storedMessage.Previous) else if (message == storedMessage.Previous?.Id)
_cache[channel] = new CachedMessage(storedMessage.Id, storedMessage.ReferencedMessage, null); _cache[channel] = new(storedMessage.Current, null);
} }
public void HandleMessageDeletion(ulong channel, List<ulong> messages) public void HandleMessageDeletion(ulong channel, List<ulong> messages)
@ -44,21 +47,21 @@ namespace PluralKit.Bot
if (storedMessage == null) if (storedMessage == null)
return; 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 // none of the deleted messages are relevant to the cache
return; return;
ulong? newLastMessage = null; ulong? newLastMessage = null;
if (messages.Contains(storedMessage.Id)) if (messages.Contains(storedMessage.Current.Id))
newLastMessage = storedMessage.Previous; newLastMessage = storedMessage.Previous?.Id;
if (storedMessage.Previous != null && messages.Contains(storedMessage.Previous.Value)) if (storedMessage.Previous != null && messages.Contains(storedMessage.Previous.Id))
if (newLastMessage == storedMessage.Previous) if (newLastMessage == storedMessage.Previous?.Id)
newLastMessage = null; newLastMessage = null;
else else
{ {
_cache[channel] = new CachedMessage(storedMessage.Id, storedMessage.ReferencedMessage, null); _cache[channel] = new(storedMessage.Current, null);
return; 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);
} }

View File

@ -14,7 +14,7 @@ namespace PluralKit.Core
_logger.Debug("Stored message {@StoredMessage} in channel {Channel}", msg, msg.Channel); _logger.Debug("Stored message {@StoredMessage} in channel {Channel}", msg, msg.Channel);
} }
public async Task<FullMessage> GetMessage(IPKConnection conn, ulong id) public async Task<FullMessage?> GetMessage(IPKConnection conn, ulong id)
{ {
FullMessage Mapper(PKMessage msg, PKMember member, PKSystem system) => FullMessage Mapper(PKMessage msg, PKMember member, PKSystem system) =>
new FullMessage {Message = msg, System = system, Member = member}; new FullMessage {Message = msg, System = system, Member = member};