blockmine 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/cli.js +11 -14
- package/backend/src/api/routes/bots.js +4 -1
- package/backend/src/api/routes/servers.js +1 -0
- package/backend/src/core/BotManager.js +62 -29
- package/backend/src/core/BotProcess.js +47 -16
- package/backend/src/server.js +13 -4
- package/package.json +1 -1
- package/backend/src/core/system/CommandHandler.js +0 -98
package/backend/cli.js
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
6
|
const { startServer } = require('./src/server.js');
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
const DATA_DIR = path.join(os.homedir(), '.blockmine');
|
|
10
|
-
if (!fs.existsSync(DATA_DIR)) {
|
|
11
|
-
console.log(`[BlockMine] Создание папки для данных: ${DATA_DIR}`);
|
|
12
|
-
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
process.env.DATABASE_URL = `file:${path.join(DATA_DIR, 'blockmine.db')}`;
|
|
16
|
-
|
|
17
9
|
const prismaSchemaPath = path.join(__dirname, 'prisma', 'schema.prisma');
|
|
18
10
|
|
|
19
|
-
|
|
20
11
|
function runCommand(command) {
|
|
21
12
|
try {
|
|
22
13
|
console.log(`> ${command}`);
|
|
23
|
-
|
|
14
|
+
const shell = process.platform === 'win32' ? 'cmd.exe' : '/bin/sh';
|
|
15
|
+
execSync(command, { stdio: 'inherit', cwd: __dirname, shell: shell });
|
|
24
16
|
} catch (e) {
|
|
25
17
|
console.error(`Команда "${command}" не удалась:`, e);
|
|
26
18
|
process.exit(1);
|
|
@@ -29,12 +21,17 @@ function runCommand(command) {
|
|
|
29
21
|
|
|
30
22
|
async function main() {
|
|
31
23
|
console.log('Запуск панели управления BlockMine...');
|
|
32
|
-
console.log(`[BlockMine] Хранилище данных: ${DATA_DIR}`);
|
|
33
24
|
|
|
34
|
-
const
|
|
35
|
-
|
|
25
|
+
const dbPath = path.join(DATA_DIR, 'blockmine.db');
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(dbPath)) {
|
|
36
28
|
console.log('База данных не найдена. Создаем и применяем все миграции...');
|
|
37
29
|
runCommand(`npx prisma migrate deploy --schema=${prismaSchemaPath}`);
|
|
30
|
+
|
|
31
|
+
console.log('Заполнение базы данных начальными данными (серверами)...');
|
|
32
|
+
const seedScriptPath = path.join(__dirname, 'prisma', 'seed.js');
|
|
33
|
+
runCommand(`node ${seedScriptPath}`);
|
|
34
|
+
|
|
38
35
|
console.log('Первоначальная настройка базы данных завершена.');
|
|
39
36
|
} else {
|
|
40
37
|
console.log('Проверка и применение обновлений базы данных...');
|
|
@@ -55,7 +55,10 @@ router.get('/', async (req, res) => {
|
|
|
55
55
|
try {
|
|
56
56
|
const bots = await prisma.bot.findMany({ include: { server: true }, orderBy: { createdAt: 'asc' } });
|
|
57
57
|
res.json(bots);
|
|
58
|
-
} catch (error) {
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error("[API /api/bots] Ошибка получения списка ботов:", error);
|
|
60
|
+
res.status(500).json({ error: 'Не удалось получить список ботов' });
|
|
61
|
+
}
|
|
59
62
|
});
|
|
60
63
|
|
|
61
64
|
router.get('/state', (req, res) => {
|
|
@@ -8,6 +8,7 @@ router.get('/', async (req, res) => {
|
|
|
8
8
|
const servers = await prisma.server.findMany({ orderBy: { name: 'asc' } });
|
|
9
9
|
res.json(servers);
|
|
10
10
|
} catch (error) {
|
|
11
|
+
console.error("[API /api/servers] Ошибка получения списка серверов:", error);
|
|
11
12
|
res.status(500).json({ error: 'Не удалось получить список серверов' });
|
|
12
13
|
}
|
|
13
14
|
});
|
|
@@ -111,27 +111,20 @@ class BotManager {
|
|
|
111
111
|
|
|
112
112
|
const enabledPlugins = allPluginsForBot.filter(p => p.isEnabled);
|
|
113
113
|
|
|
114
|
-
const { sortedPlugins, pluginInfo } = DependencyService.resolveDependencies(enabledPlugins, allPluginsForBot);
|
|
114
|
+
const { sortedPlugins, pluginInfo, hasCriticalIssues } = DependencyService.resolveDependencies(enabledPlugins, allPluginsForBot);
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.appendLog(botConfig.id, '[DependencyManager] Обнаружены проблемы с зависимостями:');
|
|
116
|
+
if (hasCriticalIssues) {
|
|
117
|
+
this.appendLog(botConfig.id, '[DependencyManager] Обнаружены критические проблемы с зависимостями:');
|
|
119
118
|
for (const plugin of Object.values(pluginInfo)) {
|
|
120
119
|
if (plugin.issues.length > 0) {
|
|
121
120
|
this.appendLog(botConfig.id, ` - Плагин "${plugin.name}":`);
|
|
122
121
|
for (const issue of plugin.issues) {
|
|
123
122
|
const logMessage = ` - [${issue.type.toUpperCase()}] ${issue.message}`;
|
|
124
123
|
this.appendLog(botConfig.id, logMessage);
|
|
125
|
-
if (['missing_dependency', 'version_mismatch', 'circular_dependency'].includes(issue.type)) {
|
|
126
|
-
canStart = false;
|
|
127
|
-
}
|
|
128
124
|
}
|
|
129
125
|
}
|
|
130
126
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (!canStart) {
|
|
134
|
-
this.appendLog(botConfig.id, '[DependencyManager] [FATAL] Запуск отменен из-за критических ошибок в зависимостях.');
|
|
127
|
+
this.appendLog(botConfig.id, '[DependencyManager] [FATAL] Запуск отменен.');
|
|
135
128
|
this.emitStatusUpdate(botConfig.id, 'stopped', 'Ошибка зависимостей плагинов.');
|
|
136
129
|
return { success: false, message: 'Критические ошибки в зависимостях плагинов.' };
|
|
137
130
|
}
|
|
@@ -156,6 +149,8 @@ class BotManager {
|
|
|
156
149
|
this.emitStatusUpdate(botConfig.id, message.status);
|
|
157
150
|
} else if (message.type === 'validate_and_run_command') {
|
|
158
151
|
await this.handleCommandValidation(botConfig, message);
|
|
152
|
+
} else if (message.type === 'register_command') {
|
|
153
|
+
await this.handleCommandRegistration(botConfig.id, message.commandConfig);
|
|
159
154
|
}
|
|
160
155
|
});
|
|
161
156
|
|
|
@@ -180,41 +175,39 @@ class BotManager {
|
|
|
180
175
|
try {
|
|
181
176
|
const user = await RealUserService.getUser(username, botConfig.id, botConfig);
|
|
182
177
|
|
|
183
|
-
if (user.isBlacklisted)
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
178
|
+
if (user.isBlacklisted) return;
|
|
186
179
|
|
|
187
|
-
const dbCommand = await prisma.command.
|
|
180
|
+
const dbCommand = await prisma.command.findFirst({
|
|
181
|
+
where: {
|
|
182
|
+
botId: botConfig.id,
|
|
183
|
+
OR: [ { name: commandName }, { aliases: { contains: `"${commandName}"` } } ]
|
|
184
|
+
}
|
|
185
|
+
});
|
|
188
186
|
|
|
189
|
-
if (!dbCommand || (!dbCommand.isEnabled && !user.isOwner))
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
187
|
+
if (!dbCommand || (!dbCommand.isEnabled && !user.isOwner)) return;
|
|
192
188
|
|
|
193
189
|
const allowedTypes = JSON.parse(dbCommand.allowedChatTypes || '[]');
|
|
194
190
|
if (!allowedTypes.includes(typeChat) && !user.isOwner) {
|
|
195
|
-
|
|
196
|
-
this.sendMessageToBot(botConfig.id, replyMessage, 'private', username);
|
|
191
|
+
this.sendMessageToBot(botConfig.id, `Команду ${dbCommand.name} нельзя использовать в этом типе чата.`, 'private', username);
|
|
197
192
|
return;
|
|
198
193
|
}
|
|
199
194
|
|
|
200
195
|
const permission = dbCommand.permissionId ? await prisma.permission.findUnique({ where: { id: dbCommand.permissionId } }) : null;
|
|
201
196
|
if (permission && !user.hasPermission(permission.name)) {
|
|
202
|
-
|
|
203
|
-
this.sendMessageToBot(botConfig.id, replyMessage, typeChat, username);
|
|
197
|
+
this.sendMessageToBot(botConfig.id, `У вас нет прав для выполнения команды ${dbCommand.name}.`, 'private', username);
|
|
204
198
|
return;
|
|
205
199
|
}
|
|
206
200
|
|
|
207
201
|
const domain = (permission?.name || '').split('.')[0] || 'user';
|
|
208
202
|
const bypassCooldownPermission = `${domain}.cooldown.bypass`;
|
|
209
203
|
if (dbCommand.cooldown > 0 && !user.isOwner && !user.hasPermission(bypassCooldownPermission)) {
|
|
210
|
-
const cooldownKey = `${botConfig.id}:${
|
|
204
|
+
const cooldownKey = `${botConfig.id}:${dbCommand.name}:${user.id}`;
|
|
211
205
|
const now = Date.now();
|
|
212
206
|
const lastUsed = cooldowns.get(cooldownKey);
|
|
213
207
|
|
|
214
208
|
if (lastUsed && (now - lastUsed < dbCommand.cooldown * 1000)) {
|
|
215
209
|
const timeLeft = Math.ceil((dbCommand.cooldown * 1000 - (now - lastUsed)) / 1000);
|
|
216
|
-
|
|
217
|
-
this.sendMessageToBot(botConfig.id, replyMessage, typeChat, username);
|
|
210
|
+
this.sendMessageToBot(botConfig.id, `Команду ${dbCommand.name} можно будет использовать через ${timeLeft} сек.`, typeChat, username);
|
|
218
211
|
return;
|
|
219
212
|
}
|
|
220
213
|
cooldowns.set(cooldownKey, now);
|
|
@@ -222,13 +215,54 @@ class BotManager {
|
|
|
222
215
|
|
|
223
216
|
const child = this.bots.get(botConfig.id);
|
|
224
217
|
if (child) {
|
|
225
|
-
child.send({ type: 'execute_handler', commandName, username, args, typeChat });
|
|
218
|
+
child.send({ type: 'execute_handler', commandName: dbCommand.name, username, args, typeChat });
|
|
226
219
|
}
|
|
227
220
|
|
|
228
221
|
} catch (error) {
|
|
229
222
|
console.error(`[BotManager] Ошибка валидации команды ${commandName}:`, error);
|
|
230
|
-
|
|
231
|
-
|
|
223
|
+
this.sendMessageToBot(botConfig.id, `Произошла внутренняя ошибка при выполнении команды.`, 'private', username);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async handleCommandRegistration(botId, commandConfig) {
|
|
228
|
+
try {
|
|
229
|
+
let permissionId = null;
|
|
230
|
+
if (commandConfig.permissions) {
|
|
231
|
+
let permission = await prisma.permission.findUnique({
|
|
232
|
+
where: { botId_name: { botId, name: commandConfig.permissions } }
|
|
233
|
+
});
|
|
234
|
+
if (!permission) {
|
|
235
|
+
permission = await prisma.permission.create({
|
|
236
|
+
data: {
|
|
237
|
+
botId,
|
|
238
|
+
name: commandConfig.permissions,
|
|
239
|
+
description: `Авто-создано для команды ${commandConfig.name}`,
|
|
240
|
+
owner: commandConfig.owner,
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
permissionId = permission.id;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
await prisma.command.upsert({
|
|
248
|
+
where: { botId_name: { botId, name: commandConfig.name } },
|
|
249
|
+
update: {
|
|
250
|
+
description: commandConfig.description,
|
|
251
|
+
aliases: JSON.stringify(commandConfig.aliases || []),
|
|
252
|
+
owner: commandConfig.owner,
|
|
253
|
+
permissionId: permissionId,
|
|
254
|
+
allowedChatTypes: JSON.stringify(commandConfig.allowedChatTypes || ['chat', 'private']),
|
|
255
|
+
},
|
|
256
|
+
create: {
|
|
257
|
+
...commandConfig,
|
|
258
|
+
botId,
|
|
259
|
+
aliases: JSON.stringify(commandConfig.aliases || []),
|
|
260
|
+
allowedChatTypes: JSON.stringify(commandConfig.allowedChatTypes || ['chat', 'private']),
|
|
261
|
+
permissionId: permissionId,
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error(`[BotManager] Ошибка при регистрации команды '${commandConfig.name}' от плагина:`, error);
|
|
232
266
|
}
|
|
233
267
|
}
|
|
234
268
|
|
|
@@ -244,7 +278,6 @@ class BotManager {
|
|
|
244
278
|
sendMessageToBot(botId, message, chatType = 'command', username = null) {
|
|
245
279
|
const child = this.bots.get(botId);
|
|
246
280
|
if (child) {
|
|
247
|
-
// Отправляем объект с полной информацией
|
|
248
281
|
child.send({ type: 'chat', payload: { message, chatType, username } });
|
|
249
282
|
return { success: true };
|
|
250
283
|
}
|
|
@@ -21,10 +21,7 @@ function sendLog(content) {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
* Анализирует входящее сообщение и отправляет запрос на валидацию команды в главный процесс.
|
|
26
|
-
*/
|
|
27
|
-
async function handleIncomingChat(type, username, message) {
|
|
24
|
+
function handleIncomingCommand(type, username, message) {
|
|
28
25
|
if (!message.startsWith(bot.config.prefix || '@')) return;
|
|
29
26
|
|
|
30
27
|
const rawMessage = message.slice((bot.config.prefix || '@').length).trim();
|
|
@@ -38,13 +35,47 @@ async function handleIncomingChat(type, username, message) {
|
|
|
38
35
|
if (!commandInstance) return;
|
|
39
36
|
|
|
40
37
|
try {
|
|
41
|
-
const
|
|
38
|
+
const processedArgs = {};
|
|
39
|
+
const parsedArgs = parseArguments(restOfMessage);
|
|
40
|
+
let currentArgIndex = 0;
|
|
41
|
+
|
|
42
|
+
for (const argDef of commandInstance.args) {
|
|
43
|
+
if (argDef.type === 'greedy_string') {
|
|
44
|
+
if (currentArgIndex < parsedArgs.length) {
|
|
45
|
+
processedArgs[argDef.name] = parsedArgs.slice(currentArgIndex).join(' ');
|
|
46
|
+
currentArgIndex = parsedArgs.length;
|
|
47
|
+
}
|
|
48
|
+
} else if (currentArgIndex < parsedArgs.length) {
|
|
49
|
+
let value = parsedArgs[currentArgIndex];
|
|
50
|
+
if (argDef.type === 'number') {
|
|
51
|
+
const numValue = parseFloat(value);
|
|
52
|
+
if (isNaN(numValue)) {
|
|
53
|
+
bot.api.sendMessage(type, `Ошибка: Неверный тип аргумента "${argDef.description}". Ожидалось число.`, username);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
value = numValue;
|
|
57
|
+
}
|
|
58
|
+
processedArgs[argDef.name] = value;
|
|
59
|
+
currentArgIndex++;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (processedArgs[argDef.name] === undefined) {
|
|
63
|
+
if (argDef.required) {
|
|
64
|
+
bot.api.sendMessage(type, `Ошибка: Необходимо указать: ${argDef.description}`, username);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (argDef.default !== undefined) {
|
|
68
|
+
processedArgs[argDef.name] = argDef.default;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
42
73
|
if (process.send) {
|
|
43
74
|
process.send({
|
|
44
75
|
type: 'validate_and_run_command',
|
|
45
76
|
commandName: commandInstance.name,
|
|
46
77
|
username,
|
|
47
|
-
args,
|
|
78
|
+
args: processedArgs,
|
|
48
79
|
typeChat: type
|
|
49
80
|
});
|
|
50
81
|
}
|
|
@@ -147,12 +178,13 @@ process.on('message', async (message) => {
|
|
|
147
178
|
let messageHandledByCustomParser = false;
|
|
148
179
|
|
|
149
180
|
bot.events.on('chat:message', (data) => {
|
|
150
|
-
|
|
181
|
+
const { type, username, message } = data;
|
|
182
|
+
if (username && message) {
|
|
151
183
|
messageHandledByCustomParser = true;
|
|
152
|
-
|
|
184
|
+
handleIncomingCommand(type, username, message);
|
|
153
185
|
}
|
|
154
186
|
});
|
|
155
|
-
|
|
187
|
+
|
|
156
188
|
bot.on('message', (jsonMsg) => {
|
|
157
189
|
const ansiMessage = jsonMsg.toAnsi();
|
|
158
190
|
if (ansiMessage.trim()) {
|
|
@@ -168,8 +200,7 @@ process.on('message', async (message) => {
|
|
|
168
200
|
if (messageHandledByCustomParser) {
|
|
169
201
|
return;
|
|
170
202
|
}
|
|
171
|
-
|
|
172
|
-
handleIncomingChat('chat', username, message);
|
|
203
|
+
handleIncomingCommand('chat', username, message);
|
|
173
204
|
});
|
|
174
205
|
|
|
175
206
|
bot.on('login', () => {
|
|
@@ -205,11 +236,11 @@ process.on('message', async (message) => {
|
|
|
205
236
|
if (bot) bot.quit();
|
|
206
237
|
else process.exit(0);
|
|
207
238
|
} else if (message.type === 'chat') {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} else if (message.type === 'execute_handler') {
|
|
239
|
+
if (bot && bot.entity) {
|
|
240
|
+
const { message: msg, chatType, username } = message.payload;
|
|
241
|
+
bot.messageQueue.enqueue(chatType, msg, username);
|
|
242
|
+
}
|
|
243
|
+
} else if (message.type === 'execute_handler') {
|
|
213
244
|
const { commandName, username, args, typeChat } = message;
|
|
214
245
|
const commandInstance = bot.commands.get(commandName);
|
|
215
246
|
if (commandInstance) {
|
package/backend/src/server.js
CHANGED
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
const express = require('express');
|
|
3
3
|
const http = require('http');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const fs = require('fs
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
const DATA_DIR = path.join(os.homedir(), '.blockmine');
|
|
9
|
+
if (!fs.existsSync(DATA_DIR)) {
|
|
10
|
+
console.log(`[Server] Создание папки для данных: ${DATA_DIR}`);
|
|
11
|
+
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
process.env.DATABASE_URL = `file:${path.join(DATA_DIR, 'blockmine.db')}`;
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
const { initializeSocket } = require('./real-time/socketHandler');
|
|
7
18
|
const botRoutes = require('./api/routes/bots');
|
|
8
19
|
const pluginRoutes = require('./api/routes/plugins');
|
|
@@ -24,7 +35,7 @@ const rootPath = path.join(__dirname, '..', '..');
|
|
|
24
35
|
app.get('/api/version', async (req, res) => {
|
|
25
36
|
try {
|
|
26
37
|
const packageJsonPath = path.join(rootPath, 'package.json');
|
|
27
|
-
const packageJsonData = await fs.readFile(packageJsonPath, 'utf-8');
|
|
38
|
+
const packageJsonData = await fs.promises.readFile(packageJsonPath, 'utf-8');
|
|
28
39
|
const { version } = JSON.parse(packageJsonData);
|
|
29
40
|
res.json({ version });
|
|
30
41
|
} catch (error) {
|
|
@@ -38,7 +49,6 @@ app.use('/api/plugins', pluginRoutes);
|
|
|
38
49
|
app.use('/api/servers', serverRoutes);
|
|
39
50
|
app.use('/api/permissions', permissionsRoutes);
|
|
40
51
|
|
|
41
|
-
|
|
42
52
|
app.use(express.static(frontendPath));
|
|
43
53
|
|
|
44
54
|
app.get(/^(?!\/api).*/, (req, res) => {
|
|
@@ -50,7 +60,6 @@ app.get(/^(?!\/api).*/, (req, res) => {
|
|
|
50
60
|
});
|
|
51
61
|
});
|
|
52
62
|
|
|
53
|
-
|
|
54
63
|
async function startServer() {
|
|
55
64
|
return new Promise((resolve) => {
|
|
56
65
|
server.listen(PORT, () => {
|
package/package.json
CHANGED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
const { PrismaClient } = require('@prisma/client');
|
|
2
|
-
const prisma = new PrismaClient();
|
|
3
|
-
const User = require('../UserService');
|
|
4
|
-
const { parseArguments } = require('./parseArguments');
|
|
5
|
-
|
|
6
|
-
const cooldowns = new Map();
|
|
7
|
-
|
|
8
|
-
async function commandHandler(bot, typeChat, username, message) {
|
|
9
|
-
if (!message.startsWith(bot.config.prefix || '@')) return;
|
|
10
|
-
|
|
11
|
-
const rawMessage = message.slice((bot.config.prefix || '@').length).trim();
|
|
12
|
-
|
|
13
|
-
const commandParts = rawMessage.split(/ +/);
|
|
14
|
-
const commandName = commandParts.shift().toLowerCase();
|
|
15
|
-
const restOfMessage = commandParts.join(' ');
|
|
16
|
-
|
|
17
|
-
const commandInstance = bot.commands.get(commandName);
|
|
18
|
-
|
|
19
|
-
if (!commandInstance) return;
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const user = await User.getUser(username, bot.config.id, bot.config);
|
|
23
|
-
|
|
24
|
-
if (user.isBlacklisted) {
|
|
25
|
-
return commandInstance.onBlacklisted(bot, typeChat, user);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const dbCommand = await prisma.command.findUnique({ where: { botId_name: { botId: bot.config.id, name: commandInstance.name } } });
|
|
29
|
-
|
|
30
|
-
if (!dbCommand || (!dbCommand.isEnabled && !user.isOwner)) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const allowedTypes = JSON.parse(dbCommand.allowedChatTypes || '[]');
|
|
35
|
-
if (!allowedTypes.includes(typeChat) && !user.isOwner) {
|
|
36
|
-
return commandInstance.onWrongChatType(bot, typeChat, user);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (!user.hasPermission(commandInstance.permissions)) {
|
|
40
|
-
return commandInstance.onInsufficientPermissions(bot, typeChat, user);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const processedArgs = {};
|
|
44
|
-
const parsedArgs = parseArguments(restOfMessage);
|
|
45
|
-
let currentArgIndex = 0;
|
|
46
|
-
|
|
47
|
-
for (const argDef of commandInstance.args) {
|
|
48
|
-
if (argDef.type === 'greedy_string') {
|
|
49
|
-
if (currentArgIndex < parsedArgs.length) {
|
|
50
|
-
processedArgs[argDef.name] = parsedArgs.slice(currentArgIndex).join(' ');
|
|
51
|
-
currentArgIndex = parsedArgs.length;
|
|
52
|
-
}
|
|
53
|
-
} else if (currentArgIndex < parsedArgs.length) {
|
|
54
|
-
let value = parsedArgs[currentArgIndex];
|
|
55
|
-
if (argDef.type === 'number') {
|
|
56
|
-
const numValue = parseFloat(value);
|
|
57
|
-
if (isNaN(numValue)) {
|
|
58
|
-
return commandInstance.onInvalidArguments(bot, typeChat, user, { message: `Неверный тип аргумента "${argDef.description}". Ожидалось число.` });
|
|
59
|
-
}
|
|
60
|
-
value = numValue;
|
|
61
|
-
}
|
|
62
|
-
processedArgs[argDef.name] = value;
|
|
63
|
-
currentArgIndex++;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (processedArgs[argDef.name] === undefined) {
|
|
67
|
-
if (argDef.required) {
|
|
68
|
-
return commandInstance.onInvalidArguments(bot, typeChat, user, { message: `Необходимо указать: ${argDef.description}` });
|
|
69
|
-
}
|
|
70
|
-
if (argDef.default !== undefined) {
|
|
71
|
-
processedArgs[argDef.name] = argDef.default;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const domain = (commandInstance.permissions || '').split('.')[0] || 'user';
|
|
77
|
-
const bypassCooldownPermission = `${domain}.cooldown.bypass`;
|
|
78
|
-
if (dbCommand.cooldown > 0 && !user.isOwner && !user.hasPermission(bypassCooldownPermission)) {
|
|
79
|
-
const cooldownKey = `${bot.config.id}:${commandName}:${user.id}`;
|
|
80
|
-
const now = Date.now();
|
|
81
|
-
const lastUsed = cooldowns.get(cooldownKey);
|
|
82
|
-
|
|
83
|
-
if (lastUsed && (now - lastUsed < dbCommand.cooldown * 1000)) {
|
|
84
|
-
const timeLeft = Math.ceil((dbCommand.cooldown * 1000 - (now - lastUsed)) / 1000);
|
|
85
|
-
return commandInstance.onCooldown(bot, typeChat, user, timeLeft);
|
|
86
|
-
}
|
|
87
|
-
cooldowns.set(cooldownKey, now);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
await commandInstance.handler(bot, typeChat, user, processedArgs);
|
|
91
|
-
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error(`[CommandHandler] Ошибка выполнения команды ${commandName}:`, error);
|
|
94
|
-
bot.api.sendMessage('private', `Произошла ошибка при выполнении команды.`, username);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
module.exports = { commandHandler };
|