From 2a43ad7febefd307c3873268b91c98abf4c70437 Mon Sep 17 00:00:00 2001 From: "Navy.gif" Date: Fri, 12 Jul 2024 16:25:13 +0300 Subject: [PATCH] More debug logging, added dev command to enable debug logging in specific guild --- @types/Guild.d.ts | 1 + options.json | 1 + .../components/commands/developer/Debug.ts | 59 +++++++ .../components/commands/moderation/Roles.ts | 4 - .../components/wrappers/GuildWrapper.ts | 159 ++---------------- src/client/infractions/Addrole.ts | 2 + src/client/infractions/Ban.ts | 1 + src/client/infractions/Kick.ts | 2 + src/client/infractions/Removerole.ts | 1 + src/client/infractions/Unban.ts | 1 + src/client/infractions/Unmute.ts | 6 +- src/client/interfaces/Infraction.ts | 4 + tsconfig.json | 2 +- 13 files changed, 87 insertions(+), 156 deletions(-) create mode 100644 src/client/components/commands/developer/Debug.ts diff --git a/@types/Guild.d.ts b/@types/Guild.d.ts index e815b43..2794b6b 100644 --- a/@types/Guild.d.ts +++ b/@types/Guild.d.ts @@ -120,6 +120,7 @@ export type GuildData = { caseId?: number, settings?: GuildSettings, premium?: number, + debug?: boolean, _version?: string, _imported?: { [key: string]: boolean | undefined, diff --git a/options.json b/options.json index 2712c35..c1ce5b6 100644 --- a/options.json +++ b/options.json @@ -69,6 +69,7 @@ "tables": [ "guilds", "attachments", + "messages", "permissions", "webhooks", "wordwatcher", diff --git a/src/client/components/commands/developer/Debug.ts b/src/client/components/commands/developer/Debug.ts new file mode 100644 index 0000000..6a90749 --- /dev/null +++ b/src/client/components/commands/developer/Debug.ts @@ -0,0 +1,59 @@ +import { CommandOptionType, CommandParams } from '../../../../../@types/Client.js'; +import DiscordClient from '../../../DiscordClient.js'; +import { Command } from '../../../interfaces/index.js'; +import InvokerWrapper from '../../wrappers/InvokerWrapper.js'; + +class DebugCommand extends Command +{ + constructor (client: DiscordClient) + { + super(client, { + name: 'debug', + restricted: true, + moduleName: 'developer', + options: [ + { name: 'guild', required: true }, + { name: 'enabled', required: true, type: CommandOptionType.BOOLEAN } + ] + }); + } + + async execute (_invoker: InvokerWrapper, options: CommandParams) + { + const guildId = options.guild!.asString; + return this.enableDebug(guildId, options.enabled?.asBool); + } + + async enableDebug (guildId: string, enabled = false) + { + let output = ''; + if (this.client.shard) + { + const result = await this.client.shard.broadcastEval(async (client, context) => + { + const bot = client as DiscordClient; + const wrapper = await bot.getGuildWrapper(context.guildId); + if (!wrapper) + return false; + await wrapper.setDebug(context.enabled); + return `${wrapper.name} (${wrapper.id})`; + }, { context: { guildId, enabled } }); + + if (!result.some(val => val)) + return 'No such guild'; + output = result.find(entry => entry) as string; + } + else + { + const wrapper = await this.client.getGuildWrapper(guildId).catch(() => null); + if (!wrapper) + return 'No such guild'; + await wrapper.setDebug(enabled); + output = `${wrapper.name} (${wrapper.id})`; + } + return `${enabled ? 'Enabled' : 'Disabled'} debug on **${output}**`; + } + +} + +export default DebugCommand; \ No newline at end of file diff --git a/src/client/components/commands/moderation/Roles.ts b/src/client/components/commands/moderation/Roles.ts index 1e57aaf..e6e0a8f 100644 --- a/src/client/components/commands/moderation/Roles.ts +++ b/src/client/components/commands/moderation/Roles.ts @@ -8,7 +8,6 @@ import MemberWrapper from '../../wrappers/MemberWrapper.js'; class AddroleCommand extends ModerationCommand { - constructor (client: DiscordClient) { super(client, { @@ -43,12 +42,10 @@ class AddroleCommand extends ModerationCommand clientPermissions: [ 'ManageRoles' ], skipOptions: [ 'points', 'expiration', 'force', 'prune' ] }); - } async execute (invoker: InvokerWrapper, { users, roles, ...args }: CommandParams) { - if (!users) throw new CommandError(invoker, { index: 'MODERATION_MISSING_USERS' }); if (!roles) @@ -66,7 +63,6 @@ class AddroleCommand extends ModerationCommand roles: roles.asString } }); - } } diff --git a/src/client/components/wrappers/GuildWrapper.ts b/src/client/components/wrappers/GuildWrapper.ts index c967d8b..cdbec0b 100644 --- a/src/client/components/wrappers/GuildWrapper.ts +++ b/src/client/components/wrappers/GuildWrapper.ts @@ -59,89 +59,9 @@ class GuildWrapper this.#guild = guild; this.#webhooks = new Collection(); this.#memberWrappers = new Collection(); - this.#debugLog('Created wrapper'); + this.debug('Created wrapper'); } - // async createPoll ({ user, duration, ...opts }: PollData) - // { - // // Idk polls that don't have a duration should still be stored somewhere so they can be ended at an arbitrary point - // const type = 'poll'; - // const now = Date.now(); - // const id = `${type}:${user}:${now}`; - // const data = { ...opts, user, id, guild: this.id, type, time: duration * 1000, created: now }; - // if (duration) - // await this.createCallback(data satisfies CallbackData); - // } - - // async loadCallbacks () - // { - // const data = await this.#client.mongodb.callbacks.find({ guild: this.id }); - // for (const cb of data) - // await this.createCallback(cb, false); - // } - - // async createCallback (data: CallbackData, update = true) - // { - // const handler = this[`_${data.type}`] as CallbackFn;// .bind(this); - // if (!handler) - // throw new Error('Invalid callback type'); - - // const now = Date.now(); - // const time = data.created + data.time; - // const diff = time - now; - // if (diff < 5000) - // return handler.bind(this)(data); - - // const cb = { timeout: setTimeout(handler.bind(this), diff, data), data }; - // this.#callbacks.set(data.id, cb); - // if (update) - // await this.#client.mongodb.callbacks.updateOne({ id: data.id, guild: this.id }, { $set: data }); - // } - - // async removeCallback (id: string) - // { - // const cb = this.#callbacks.get(id); - // if (cb) - // clearTimeout(cb.timeout); - // this.#callbacks.delete(id); - // await this.#client.mongodb.callbacks.deleteOne({ guild: this.id, id }); - // } - - // async _poll ({ user, message, channel, id, questions, startedIn }: PollData & CallbackData) - // { // multichoice, - // const startedInChannel = await this.resolveChannel(startedIn); - // const pollChannel = await this.resolveChannel(channel); - // if (pollChannel) - // { - // const msg = await pollChannel.messages.fetch(message).catch(() => null); - // if (msg) - // { - // const { reactions } = msg; - // const reactionEmojis = questions.length ? PollReactions.Multi : PollReactions.Single; - // const result: {[key: string]: number} = {}; - // for (const emoji of reactionEmojis) - // { - // let reaction = reactions.resolve(emoji); - // // eslint-disable-next-line max-depth - // if (!reaction) - // continue; - // // eslint-disable-next-line max-depth - // if (reaction.partial) - // reaction = await reaction.fetch(); - // result[emoji] = reaction.count - 1; - // } - - // const embed = msg.embeds[0].toJSON(); - // const results = Object.entries(result).map(([ emoji, count ]) => `${emoji} - ${count}`).join('\n'); - // embed.description = this.format('COMMAND_POLL_END', { results }); - // await msg.edit({ embeds: [ embed ] }); - // } - // } - // await this.removeCallback(id); - // if (startedInChannel) - // await startedInChannel.send(this.format('COMMAND_POLL_NOTIFY_STARTER', { user, channel })); - // } - async filterText (member: GuildMember, text: string) { const settings = await this.settings(); @@ -289,72 +209,6 @@ class GuildWrapper return true; } - // async _attemptDataImport () - // { - // const migratorOptions = { - // // host: MONGODB_V2_HOST, - // database: 'galacticbot', - // version: '2' - // }; - - // const settingsMigrator = new SettingsMigrator(this.client, this, migratorOptions); - // const modlogsMigrator = new InfractionMigrator(this.client, this, migratorOptions); - - // await settingsMigrator.connect(); - // await modlogsMigrator.connect(); - - // let importedSettings = null; - // let importedModlogs = null; - - // try - // { - // importedSettings = await settingsMigrator.import(); - // importedModlogs = await modlogsMigrator.import(); - // importedModlogs.sort((a, b) => a.case - b.case); - // } - // catch (err) - // { - // await settingsMigrator.end(); - // await modlogsMigrator.end(); - // // Did not find old settings, marking as imported anyway - // if (err.message.includes('No old')) - // { - // await this.updateData({ _imported: { settings: true, modlogs: true } }); - // } - // else - // this.client.logger.error(err.stack); - // return null; - // } - // await settingsMigrator.end(); - // await modlogsMigrator.end(); - - // await this.client.mongodb.infractions.deleteMany({ guild: this.id }); - // await this.client.mongodb.infractions.insertMany(importedModlogs); - // this._data.caseId = importedModlogs[importedModlogs.length - 1].case; - // await this.updateData({ - // caseId: this._data.caseId, - // premium: importedSettings.premium, - // _imported: { settings: true, modlogs: true } - // }); - - // const { webhook, permissions, settings } = importedSettings; - // await this.updateSettings(settings); - // if (webhook) - // { - // const hooks = await this.fetchWebhooks().catch(() => null); - // const hook = hooks?.get(webhook); - // if (hook) - // await this.updateWebhook('messages', hook); - // } - - // if (permissions) - // await this.#client.mongodb.permissions.updateOne({ guildId: this.id }, permissions); - - - // return settings; - - // } - /** * Update a webhook entry in the database * @@ -528,9 +382,16 @@ class GuildWrapper this.#logger.error(`Database error (guild:${this.id}) :\n${error.stack || error}`); } - #debugLog (log: string) + debug (log: string) { - this.#logger.debug(`[${this.name}]: ${log}`); + if (!this.#data || this.#data.debug) + this.#logger.debug(`[${this.name}]: ${log}`); + } + + async setDebug (enabled: boolean) + { + await this.#client.mongodb.guilds.updateOne({ guildId: this.id }, { $set: { debug: enabled } }); + this.#data.debug = enabled; } /* Wrapper Functions */ diff --git a/src/client/infractions/Addrole.ts b/src/client/infractions/Addrole.ts index 0dc2e8e..a2f1801 100644 --- a/src/client/infractions/Addrole.ts +++ b/src/client/infractions/Addrole.ts @@ -62,10 +62,12 @@ class AddroleInfraction extends Infraction } try { + this.guild.debug(`Adding roles ${this.data.roleIds.join(', ')} to ${this.member.tag} (${this.member.id})`); await this.member.roles.add(this.data.roleIds, this._reason); } catch (error) { + this.logger.error(`Failed to add roles (${this.data.roleIds.join(', ')}) to ${this.member.tag} (${this.member.id})\n${error}`); return this._fail('INFRACTION_ERROR'); } diff --git a/src/client/infractions/Ban.ts b/src/client/infractions/Ban.ts index dbaada5..746cd9a 100644 --- a/src/client/infractions/Ban.ts +++ b/src/client/infractions/Ban.ts @@ -65,6 +65,7 @@ class BanInfraction extends Infraction } catch (error) { + this.logger.error(`Failed to ban ${(this.target as UserWrapper).tag} (${this.target!.id}) from ${this.guild.name} (${this.guild.id})\n${error}`); return this._fail('INFRACTION_ERROR'); } await this.handle(); diff --git a/src/client/infractions/Kick.ts b/src/client/infractions/Kick.ts index 5d90dc3..601a22f 100644 --- a/src/client/infractions/Kick.ts +++ b/src/client/infractions/Kick.ts @@ -4,6 +4,7 @@ import DiscordClient from '../DiscordClient.js'; import MemberWrapper from '../components/wrappers/MemberWrapper.js'; import Infraction from '../interfaces/Infraction.js'; import { KickData } from '../../../@types/Infractions.js'; +import UserWrapper from '../components/wrappers/UserWrapper.js'; class KickInfraction extends Infraction { @@ -56,6 +57,7 @@ class KickInfraction extends Infraction } catch (error) { + this.logger.error(`Failed to kick ${(this.target as UserWrapper).tag} (${this.target!.id}) from ${this.guild.name} (${this.guild.id})\n${error}`); return this._fail('INFRACTION_ERROR'); } await this.handle(); diff --git a/src/client/infractions/Removerole.ts b/src/client/infractions/Removerole.ts index 4c3722f..94e5f63 100644 --- a/src/client/infractions/Removerole.ts +++ b/src/client/infractions/Removerole.ts @@ -59,6 +59,7 @@ class RemoveroleInfraction extends Infraction } catch (error) { + this.logger.error(`Failed to remove roles (${this.data.roleIds!.join(', ')}) to ${this.member!.tag} (${this.member!.id})\n${error}`); return this._fail('INFRACTION_ERROR'); } diff --git a/src/client/infractions/Unban.ts b/src/client/infractions/Unban.ts index 867d871..9c65a73 100644 --- a/src/client/infractions/Unban.ts +++ b/src/client/infractions/Unban.ts @@ -49,6 +49,7 @@ class UnbanInfraction extends Infraction } catch (error) { + this.logger.error(`Failed to unban ${this.targetId} in ${this.guild.name} (${this.guild.id})\n${error}`); return this._fail('INFRACTION_ERROR'); } diff --git a/src/client/infractions/Unmute.ts b/src/client/infractions/Unmute.ts index 4208b54..6365d61 100644 --- a/src/client/infractions/Unmute.ts +++ b/src/client/infractions/Unmute.ts @@ -107,8 +107,9 @@ class UnmuteInfraction extends Infraction { this.member!.roles.remove(role, this._reason); } - catch (e) + catch (error) { + this.logger.error(`Failed to unmute ${this.member.tag} (${this.member.id})\n${error}`); return this._fail('C_UNMUTE_1FAIL'); } } @@ -131,8 +132,9 @@ class UnmuteInfraction extends Infraction { this.member.roles.remove(role, this._reason); } - catch (e) + catch (error) { + this.logger.error(`Failed to unmute ${this.member.tag} (${this.member.id})\n${error}`); return this._fail('C_UNMUTE_1FAIL'); } break; diff --git a/src/client/interfaces/Infraction.ts b/src/client/interfaces/Infraction.ts index 98672c4..76254ef 100644 --- a/src/client/interfaces/Infraction.ts +++ b/src/client/interfaces/Infraction.ts @@ -234,6 +234,10 @@ class Infraction }).catch(() => null); this.#dmLogMessageId = logMessage?.id ?? null; } + else + { + this.logger.debug(`Target not sendable? ${inspect(this.#target)}`); + } } if (this.#duration) diff --git a/tsconfig.json b/tsconfig.json index d4b2d78..d17bff5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -111,7 +111,7 @@ }, "compileOnSave": true, "exclude": ["archive", "api"], - "include": ["src", "index.ts", "@types"], + "include": ["src/**/*", "index.ts", "@types/*"], "watchOptions": { "watchFile": "useFsEvents", "watchDirectory": "useFsEvents",