diff --git a/backend/src/plugins/Logs/LogsPlugin.ts b/backend/src/plugins/Logs/LogsPlugin.ts index cc77ac90..4e79f583 100644 --- a/backend/src/plugins/Logs/LogsPlugin.ts +++ b/backend/src/plugins/Logs/LogsPlugin.ts @@ -1,4 +1,4 @@ -import { PluginOptions } from "knub"; +import { CooldownManager, PluginOptions } from "knub"; import DefaultLogMessages from "../../data/DefaultLogMessages.json"; import { GuildArchives } from "../../data/GuildArchives"; import { GuildCases } from "../../data/GuildCases"; @@ -267,6 +267,7 @@ export const LogsPlugin = zeppelinGuildPlugin()({ state.cases = GuildCases.getGuildInstance(guild.id); state.buffers = new Map(); + state.channelCooldowns = new CooldownManager(); state.regexRunner = getRegExpRunner(`guild-${pluginData.guild.id}`); }, diff --git a/backend/src/plugins/Logs/types.ts b/backend/src/plugins/Logs/types.ts index 71f55c65..d1905b8e 100644 --- a/backend/src/plugins/Logs/types.ts +++ b/backend/src/plugins/Logs/types.ts @@ -1,6 +1,6 @@ import * as t from "io-ts"; import { z } from "zod"; -import { BasePluginType, typedGuildEventListener } from "knub"; +import { BasePluginType, CooldownManager, typedGuildEventListener } from "knub"; import { GuildArchives } from "../../data/GuildArchives"; import { GuildCases } from "../../data/GuildCases"; import { GuildLogs } from "../../data/GuildLogs"; @@ -87,6 +87,7 @@ export interface LogsPluginType extends BasePluginType { logListener; buffers: Map; + channelCooldowns: CooldownManager; onMessageDeleteFn; onMessageDeleteBulkFn; diff --git a/backend/src/plugins/Logs/util/log.ts b/backend/src/plugins/Logs/util/log.ts index 4c2ca0f9..5f879aa3 100644 --- a/backend/src/plugins/Logs/util/log.ts +++ b/backend/src/plugins/Logs/util/log.ts @@ -6,6 +6,7 @@ import { getLogMessage } from "./getLogMessage"; import { TypedTemplateSafeValueContainer } from "../../../templateFormatter"; import { LogType } from "../../../data/LogType"; import { MessageBuffer } from "../../../utils/MessageBuffer"; +import { createChunkedMessage, isDiscordAPIError, MINUTES } from "../../../utils"; const excludedUserProps = ["user", "member", "mod"]; const excludedRoleProps = ["message.member.roles", "member.roles"]; @@ -82,6 +83,7 @@ export async function log( logChannelLoop: for (const [channelId, opts] of Object.entries(logChannels)) { const channel = pluginData.guild.channels.cache.get(channelId as Snowflake); if (!channel || !(channel instanceof TextChannel)) continue; + if (pluginData.state.channelCooldowns.isOnCooldown(channelId)) continue; if (opts.include?.length && !opts.include.includes(typeStr)) continue; if (opts.exclude && opts.exclude.includes(typeStr)) continue; if (await shouldExclude(pluginData, opts, exclusionData)) continue; @@ -102,17 +104,26 @@ export async function log( timeout: batchTime, consume: (part) => { const parse: MessageMentionTypes[] = pluginData.config.get().allow_user_mentions ? ["users"] : []; - channel - .send({ - ...part, - allowedMentions: { parse }, - }) - .catch((err) => { - // tslint:disable-next-line:no-console - console.warn( - `Error while sending ${typeStr} log to ${pluginData.guild.id}/${channelId}: ${err.message}`, - ); - }); + const promise = + part.content && !part.embeds?.length + ? createChunkedMessage(channel, part.content, { parse }) + : channel.send({ + ...part, + allowedMentions: { parse }, + }); + promise.catch((err) => { + if (isDiscordAPIError(err)) { + // Missing Access / Missing Permissions + // TODO: Show/log this somewhere + if (err.code === 50001 || err.code === 50013) { + pluginData.state.channelCooldowns.setCooldown(channelId, 2 * MINUTES); + return; + } + } + + // tslint:disable-next-line:no-console + console.warn(`Error while sending ${typeStr} log to ${pluginData.guild.id}/${channelId}: ${err.message}`); + }); }, }), );