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

Contents of /branches/5.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: 7216 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 { CommandPermissionOverwrites } from "@prisma/client";
21 import { ChatInputCommandInteraction, ContextMenuCommandInteraction, Message, Snowflake } from "discord.js";
22 import Command, { CommandMessage, ValidationRuleParsedArgs } from "../core/Command";
23 import Service from "../core/Service";
24 import { GatewayEventListener } from "../decorators/GatewayEventListener";
25 import { HasEventListeners } from "../types/HasEventListeners";
26 import { log, logError, logWarn } from "../utils/logger";
27 import { GuildConfig } from "./ConfigManager";
28
29 export const name = "commandManager";
30
31 export interface CommandContext {
32 isLegacy: boolean;
33 config: GuildConfig;
34 }
35
36 export interface LegacyCommandContext extends CommandContext {
37 isLegacy: true;
38 isContextMenu: false;
39 argv: string[];
40 args: string[];
41 parsedArgs: any[];
42 parsedNamedArgs: Record<string, any>;
43 prefix: string;
44 has(arg: string): boolean;
45 getParsedArgs<C extends Command>(command: C): ValidationRuleParsedArgs<C["validationRules"]>;
46 getParsedArg<C extends Command, I extends keyof C["validationRules"]>(
47 command: C,
48 index: I
49 ): ValidationRuleParsedArgs<C["validationRules"]>[I];
50 }
51
52 export interface ChatInputCommandContext extends CommandContext {
53 isLegacy: false;
54 isContextMenu: false;
55 options: ChatInputCommandInteraction["options"];
56 commandName: string;
57 }
58
59 export interface ContextMenuCommandContext extends CommandContext {
60 isLegacy: false;
61 isContextMenu: true;
62 options: ContextMenuCommandInteraction["options"];
63 commandName: string;
64 }
65
66 export default class CommandManager extends Service implements HasEventListeners {
67 readonly permissionOverwrites = new Map<`${Snowflake}____${string}`, CommandPermissionOverwrites>();
68
69 @GatewayEventListener("ready")
70 async onReady() {
71 log("Syncing command permission overwrites...");
72
73 const permissionOverwrites = await this.client.prisma.commandPermissionOverwrites.findMany();
74
75 for (const permissionOverwrite of permissionOverwrites) {
76 for (const command of permissionOverwrite.commands) {
77 this.permissionOverwrites.set(`${permissionOverwrite.guildId}____${command}`, permissionOverwrite);
78 }
79 }
80
81 log("Successfully synced command permission overwrites");
82 }
83
84 public async runCommandFromMessage(message: Message, checkOnly = false) {
85 if (!message.content) return;
86
87 const config = this.client.configManager.config[message.guildId!];
88
89 if (!config) {
90 logWarn("This guild is not configured: ", message.guildId!);
91 return;
92 }
93
94 const prefixes = [config.prefix];
95 let foundPrefix: string | undefined = undefined;
96
97 if (this.client.configManager.systemConfig.commands.mention_prefix && config.commands.mention_prefix) {
98 prefixes.push(`<@${this.client.user!.id}>`, `<@!${this.client.user!.id}>`);
99 }
100
101 for (const prefix of prefixes) {
102 if (message.content.startsWith(prefix)) {
103 foundPrefix = prefix;
104 break;
105 }
106 }
107
108 if (!foundPrefix) {
109 return;
110 }
111
112 const commandText = message.content.substring(foundPrefix.length).trimStart();
113 const [commandName, ...commandArguments] = commandText.split(/ +/);
114
115 const command = this.client.commands.get(commandName);
116
117 if (!command) {
118 log("Command not found, trying to find a snippet");
119 return await this.client.snippetManager.onMessageCreate(message, commandName);
120 }
121
122 if (!command.supportsLegacy) {
123 log("This command does not support legacy mode");
124 return;
125 }
126
127 command
128 .run(
129 message,
130 {
131 isLegacy: true,
132 argv: [commandName, ...commandArguments],
133 args: commandArguments,
134 config,
135 parsedArgs: [],
136 parsedNamedArgs: {},
137 isContextMenu: false,
138 prefix: foundPrefix,
139 has(arg: string) {
140 return this.args.includes(arg);
141 },
142 getParsedArg<C extends Command, I extends keyof C["validationRules"]>(command: C, index: I) {
143 return this.parsedArgs[index as number] as ValidationRuleParsedArgs<C["validationRules"]>[I];
144 },
145 getParsedArgs<C extends Command>(command: C) {
146 return this.parsedArgs as ValidationRuleParsedArgs<C["validationRules"]>;
147 }
148 } satisfies LegacyCommandContext,
149 checkOnly
150 )
151 .then(result => {
152 if (result && typeof result === "object" && "__reply" in result && result.__reply === true) {
153 message.reply(result as any).catch(console.error);
154 }
155 })
156 .catch(logError);
157
158 return true;
159 }
160
161 public async runCommandFromCommandInteraction(interaction: Exclude<CommandMessage, Message>, checkOnly = false) {
162 const config = this.client.configManager.config[interaction.guildId!];
163
164 if (!config) {
165 logWarn("This guild is not configured: ", interaction.guildId!);
166 return;
167 }
168
169 const { commandName } = interaction;
170 const command = this.client.commands.get(commandName);
171
172 if (!command) {
173 return false;
174 }
175
176 if (!command.supportsInteractions) {
177 log("This command does not support application command mode");
178 return;
179 }
180
181 command
182 .run(
183 interaction,
184 {
185 isLegacy: false,
186 config,
187 options: interaction.options,
188 isContextMenu: interaction.isContextMenuCommand(),
189 commandName
190 } as ContextMenuCommandContext | ChatInputCommandContext,
191 checkOnly
192 )
193 .then(result => {
194 if (result && typeof result === "object" && "__reply" in result && result.__reply === true) {
195 interaction.reply(result as any).catch(console.error);
196 }
197 })
198 .catch(logError);
199 }
200 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26