UNPKG

seyfert

Version:

The most advanced framework for discord bots

291 lines (290 loc) 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ComponentHandler = void 0; const collection_1 = require("../collection"); const commands_1 = require("../commands"); const common_1 = require("../common"); const componentcommand_1 = require("./componentcommand"); const modalcommand_1 = require("./modalcommand"); class ComponentHandler extends common_1.BaseHandler { client; onFail = err => this.logger.warn('<Client>.components.onFail', err); values = new Map(); // 10 minutes of timeout by default, because discord doesnt send an event when the user cancels the modal modals = new collection_1.LimitedCollection({ expire: 60e3 * 10 }); commands = []; filter = (path) => path.endsWith('.js') || (!path.endsWith('.d.ts') && path.endsWith('.ts')); constructor(logger, client) { super(logger); this.client = client; } createMatchCallback(match) { if (typeof match === 'string') return str => str === match; if (Array.isArray(match)) return str => match.includes(str); return str => match.test(str); } createComponentCollector(messageId, channelId, guildId, options = {}, components = []) { this.values.set(messageId, { messageId, channelId, guildId, options, components, idle: options.idle && options.idle > 0 ? setTimeout(() => { const old = this.clearValue(messageId); if (!old) return; options.onStop?.('idle', () => { this.createComponentCollector(messageId, channelId, guildId, options, old.components); }); }, options.idle) : undefined, timeout: options.timeout && options.timeout > 0 ? setTimeout(() => { const old = this.clearValue(messageId); if (!old) return; options.onStop?.('timeout', () => { this.createComponentCollector(messageId, channelId, guildId, options, old.components); }); }, options.timeout) : undefined, __run: (customId, callback) => { if (this.values.has(messageId)) { this.values.get(messageId).components.push({ callback, match: this.createMatchCallback(customId), }); } }, }); return { //@ts-expect-error generic run: this.values.get(messageId).__run, stop: (reason) => { const old = this.clearValue(messageId); if (!old) return; options.onStop?.(reason, () => { this.createComponentCollector(messageId, channelId, guildId, options, old.components); }); }, }; } async onComponent(id, interaction) { const row = this.values.get(id); const component = row?.components?.find(x => x.match(interaction.customId)); if (!component) return; if (row.options?.filter) { if (!(await row.options.filter(interaction))) return row.options.onPass?.(interaction); } row.idle?.refresh(); await component.callback(interaction, reason => { this.clearValue(id); row.options?.onStop?.(reason ?? 'stop', () => { this.createComponentCollector(row.messageId, row.channelId, row.guildId, row.options, row.components); }); }, () => { this.resetTimeouts(id); }); } hasComponent(id, customId) { return this.values.get(id)?.components?.some(x => x.match(customId)); } resetTimeouts(id) { const listener = this.values.get(id); if (listener) { listener.timeout?.refresh(); listener.idle?.refresh(); } } hasModal(interaction) { return this.modals.has(interaction.user.id); } onModalSubmit(interaction) { setImmediate(() => this.modals.delete(interaction.user.id)); return this.modals.get(interaction.user.id)?.(interaction); } deleteValue(id, reason) { const component = this.clearValue(id); if (!component) return; component.options?.onStop?.(reason, () => { this.createComponentCollector(component.messageId, component.channelId, component.guildId, component.options, component.components); }); } clearValue(id) { const component = this.values.get(id); if (!component) return; clearTimeout(component.timeout); clearTimeout(component.idle); this.values.delete(id); return component; } stablishDefaults(component) { component.props ??= this.client.options.commands?.defaults?.props ?? {}; const is = component instanceof modalcommand_1.ModalCommand ? 'modals' : 'components'; component.onInternalError ??= this.client.options?.[is]?.defaults?.onInternalError; component.onMiddlewaresError ??= this.client.options?.[is]?.defaults?.onMiddlewaresError; component.onRunError ??= this.client.options?.[is]?.defaults?.onRunError; component.onAfterRun ??= this.client.options?.[is]?.defaults?.onAfterRun; } set(instances) { for (const i of instances) { let component; try { component = this.callback(i); if (!component) continue; } catch (e) { this.logger.warn(e, i); continue; } this.stablishDefaults(component); this.commands.push(component); } } async load(componentsDir) { const paths = await this.loadFilesK(await this.getFiles(componentsDir)); for (const { components, file } of paths.map(x => ({ components: this.onFile(x.file), file: x }))) { if (!components) continue; for (const value of components) { let component; try { component = this.callback(value); if (!component) continue; } catch (e) { if (e instanceof Error && e.message.includes('is not a constructor')) { this.logger.warn(`${file.path .split(process.cwd()) .slice(1) .join(process.cwd())} doesn't export the class by \`export default <ComponentCommand>\``); } else this.logger.warn(e, value); continue; } if (!(component instanceof modalcommand_1.ModalCommand || component instanceof componentcommand_1.ComponentCommand)) continue; this.stablishDefaults(component); component.__filePath = file.path; this.commands.push(component); } } } async reload(path) { if (!this.client.components) return; if ((0, common_1.isCloudfareWorker)()) { throw new Error('Reload in cloudfare worker is not supported'); } const component = this.client.components.commands.find(x => x.__filePath?.endsWith(`${path}.js`) || x.__filePath?.endsWith(`${path}.ts`) || x.__filePath?.endsWith(path) || x.__filePath === path); if (!component?.__filePath) return null; delete require.cache[component.__filePath]; const index = this.client.components.commands.findIndex(x => x.__filePath === component.__filePath); if (index === -1) return null; this.client.components.commands.splice(index, 1); const imported = await (0, common_1.magicImport)(component.__filePath).then(x => x.default ?? x); const command = new imported(); command.__filePath = component.__filePath; this.client.components.commands.push(command); return imported; } async reloadAll(stopIfFail = true) { for (const i of this.commands) { try { await this.reload(i.__filePath ?? ''); } catch (e) { if (stopIfFail) { throw e; } } } } async execute(i, context) { try { const resultRunGlobalMiddlewares = await commands_1.BaseCommand.__runMiddlewares(context, (context.client.options?.globalMiddlewares ?? []), true); if (resultRunGlobalMiddlewares.pass) { return; } if ('error' in resultRunGlobalMiddlewares) { return i.onMiddlewaresError?.(context, resultRunGlobalMiddlewares.error ?? 'Unknown error'); } const resultRunMiddlewares = await commands_1.BaseCommand.__runMiddlewares(context, i.middlewares, false); if (resultRunMiddlewares.pass) { return; } if ('error' in resultRunMiddlewares) { return i.onMiddlewaresError?.(context, resultRunMiddlewares.error ?? 'Unknown error'); } try { await i.run(context); await i.onAfterRun?.(context, undefined); } catch (error) { await i.onRunError?.(context, error); await i.onAfterRun?.(context, error); } } catch (error) { try { await i.onInternalError?.(this.client, error); } catch (e) { // supress error this.logger.error(e); } } } async executeComponent(context) { for (const i of this.commands) { try { if (i.type === componentcommand_1.InteractionCommandType.COMPONENT && i.cType === context.interaction.componentType && (await i.filter(context))) { context.command = i; await this.execute(i, context); } } catch (e) { await this.onFail(e); } } } async executeModal(context) { for (const i of this.commands) { try { if (i.type === componentcommand_1.InteractionCommandType.MODAL && (await i.filter(context))) { context.command = i; await this.execute(i, context); } } catch (e) { await this.onFail(e); } } } onFile(file) { return file.default ? [file.default] : undefined; } callback(file) { return new file(); } } exports.ComponentHandler = ComponentHandler;