/[sudobot]/branches/6.x/src/services/CommandManager.ts
ViewVC logotype

Contents of /branches/6.x/src/services/CommandManager.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (show annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months ago) by rakinar2
File MIME type: application/typescript
File size: 6676 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 /**
2 * This file is part of SudoBot.
3 *
4 * Copyright (C) 2021-2023 OSN Developers.
5 *
6 * SudoBot is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * SudoBot is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 import { ChatInputCommandInteraction, ContextMenuCommandInteraction, Message } from "discord.js";
21 import { CommandMessage } from "../core/Command";
22 import Service from "../core/Service";
23 import { log, logError, logWarn } from "../utils/logger";
24 import { GuildConfig } from "./ConfigManager";
25
26 export const name = "commandManager";
27
28 export interface CommandContext {
29 isLegacy: boolean;
30 config: GuildConfig;
31 }
32
33 export interface LegacyCommandContext extends CommandContext {
34 isLegacy: true;
35 isContextMenu: false;
36 argv: string[];
37 args: string[];
38 parsedArgs: any[];
39 parsedNamedArgs: Record<string, any>;
40 prefix: string;
41 has(arg: string): boolean;
42 }
43
44 export interface ChatInputCommandContext extends CommandContext {
45 isLegacy: false;
46 isContextMenu: false;
47 options: ChatInputCommandInteraction["options"];
48 commandName: string;
49 }
50
51 export interface ContextMenuCommandContext extends CommandContext {
52 isLegacy: false;
53 isContextMenu: true;
54 options: ContextMenuCommandInteraction["options"];
55 commandName: string;
56 }
57
58 export default class CommandManager extends Service {
59 public async runCommandFromMessage(message: Message, checkOnly = false, wait: boolean = false) {
60 if (!message.content) return;
61
62 const config = this.client.configManager.config[message.guildId!];
63
64 if (!config) {
65 logWarn("This guild is not configured: ", message.guildId!);
66 return;
67 }
68
69 const prefixes = [config.prefix];
70 let foundPrefix: string | undefined = undefined;
71
72 if (this.client.configManager.systemConfig.commands.mention_prefix && config.commands.mention_prefix) {
73 prefixes.push(`<@${this.client.user!.id}>`, `<@!${this.client.user!.id}>`);
74 }
75
76 for (const prefix of prefixes) {
77 if (message.content.startsWith(prefix)) {
78 foundPrefix = prefix;
79 break;
80 }
81 }
82
83 if (!foundPrefix) {
84 return;
85 }
86
87 const commandText = message.content.substring(foundPrefix.length).trimStart();
88 const [commandName, ...commandArguments] = commandText.split(/ +/);
89
90 const command = this.client.commands.get(commandName);
91
92 if (!command) {
93 log("Command not found, trying to find a snippet");
94 return await this.client.snippetManager.onMessageCreate(message, commandName);
95 }
96
97 if (!command.supportsLegacy) {
98 log("This command does not support legacy mode");
99 return;
100 }
101
102 const context = {
103 isLegacy: true,
104 argv: [commandName, ...commandArguments],
105 args: commandArguments,
106 config,
107 parsedArgs: [],
108 parsedNamedArgs: {},
109 isContextMenu: false,
110 prefix: foundPrefix,
111 has(arg: string) {
112 return this.args.includes(arg);
113 }
114 } satisfies LegacyCommandContext;
115
116 const handlerObject = {
117 _stopped: false,
118 stopCommandExecution() {
119 this._stopped = true;
120 }
121 };
122
123 await this.client.emitWait("command", command.name, handlerObject, command, message, context);
124 await Promise.resolve();
125
126 if (handlerObject._stopped) {
127 return;
128 }
129
130 return new Promise<boolean | null>((resolve, reject) => {
131 command
132 .run({
133 context,
134 checkOnly,
135 message,
136 onAbort: wait ? () => resolve(null) : undefined
137 })
138 .then(result => {
139 if (result && typeof result === "object" && "__reply" in result && result.__reply === true) {
140 message.reply(result as any).catch(console.error);
141 }
142 if (wait) {
143 resolve(true);
144 }
145 })
146 .catch(e => {
147 logError(e);
148 reject(e);
149 });
150
151 if (!wait) {
152 resolve(true);
153 }
154 });
155 }
156
157 public async runCommandFromCommandInteraction(interaction: Exclude<CommandMessage, Message>, checkOnly = false) {
158 const config = this.client.configManager.config[interaction.guildId!];
159
160 if (!config) {
161 logWarn("This guild is not configured: ", interaction.guildId!);
162 return;
163 }
164
165 const { commandName } = interaction;
166 const command = this.client.commands.get(commandName);
167
168 if (!command) {
169 return false;
170 }
171
172 if (!command.supportsInteractions) {
173 log("This command does not support application command mode");
174 return;
175 }
176
177 const context = {
178 isLegacy: false,
179 config,
180 options: interaction.options,
181 isContextMenu: interaction.isContextMenuCommand(),
182 commandName
183 } as ContextMenuCommandContext | ChatInputCommandContext;
184
185 const handlerObject = {
186 _stopped: false,
187 stopCommandExecution() {
188 this._stopped = true;
189 }
190 };
191
192 await this.client.emitWait("command", command.name, handlerObject, command, interaction, context);
193 await Promise.resolve();
194
195 if (handlerObject._stopped) {
196 return;
197 }
198
199 command
200 .run({
201 message: interaction,
202 context,
203 checkOnly
204 })
205 .then(result => {
206 if (result && typeof result === "object" && "__reply" in result && result.__reply === true) {
207 interaction.reply(result as any).catch(console.error);
208 }
209 })
210 .catch(logError);
211 }
212 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26