From 6143be17680e547dae2932244c979d2dab45e76d Mon Sep 17 00:00:00 2001 From: FloatingMilkshake Date: Sat, 14 Sep 2024 01:34:03 -0400 Subject: [PATCH] Keyword tracking: Try to reduce number of API calls --- Helpers/KeywordTrackingHelpers.cs | 36 ++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/Helpers/KeywordTrackingHelpers.cs b/Helpers/KeywordTrackingHelpers.cs index f817443..e1b74a2 100644 --- a/Helpers/KeywordTrackingHelpers.cs +++ b/Helpers/KeywordTrackingHelpers.cs @@ -17,9 +17,32 @@ public static async Task KeywordCheck(DiscordMessage message, bool isEdit = fals return; var fields = await Program.Db.HashGetAllAsync("keywords"); + var keywordsList = fields.Select(x => JsonConvert.DeserializeObject(x.Value)).ToList(); + + // Stop! Before we make ANY API calls, does this message even contain any keywords? + if (!keywordsList.Any(x => message.Content.Contains(x.Keyword))) + return; + + // It does*. For any matched keywords, is the target user in the guild? + // *this is a broad check, we check again more specifically later (respecting other keyword properties) + foreach (var matchedKeyword in keywordsList.Where(x => message.Content.Contains(x.Keyword))) + { + try + { + await message.Channel.Guild.GetMemberAsync(matchedKeyword.UserId); + } + catch + { + // User is not in guild. Skip. + return; + } + } + + // Yes. Continue with other checks. // Get message before current to check for assumed presence // Attempt to get message from cache before fetching from Discord to avoid potential API spam + // todo: can we do this later, but without spamming the API (like repeatedly checking the same message for different keywords in the foreach loop below)? (ulong messageId, ulong authorId) msgBefore = default; var msgFoundInCache = false; if (Program.MessageCache.TryGetMessageByChannel(message.Channel.Id, out var cachedMessage)) @@ -48,18 +71,6 @@ public static async Task KeywordCheck(DiscordMessage message, bool isEdit = fals // Checks var fieldValue = JsonConvert.DeserializeObject(field.Value); - - // Try to get member; if they are not in the guild, skip - DiscordMember member; - try - { - member = await message.Channel.Guild.GetMemberAsync(fieldValue.UserId); - } - catch - { - // User is not in guild. Skip. - return; - } // If keyword is set to only match whole word, use regex to check if (fieldValue!.MatchWholeWord) @@ -109,6 +120,7 @@ public static async Task KeywordCheck(DiscordMessage message, bool isEdit = fals // Don't DM the user if their keyword was mentioned in a channel they do not have permissions to view. // If we don't do this we may leak private channels, which - even if the user might want to - I don't want to be doing. + var member = await message.Channel.Guild.GetMemberAsync(fieldValue.UserId); // need to fetch member to check permissions if (!message.Channel.PermissionsFor(member).HasPermission(Permissions.AccessChannels)) break;