blockmine 1.17.0 → 1.18.1
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/CHANGELOG.md +27 -0
- package/backend/package.json +27 -27
- package/backend/src/api/routes/bots.js +4 -3
- package/backend/src/api/routes/tasks.js +2 -1
- package/backend/src/core/BotManager.js +23 -2
- package/backend/src/core/BotProcess.js +15 -1
- package/backend/src/core/PluginLoader.js +86 -131
- package/backend/src/core/PluginManager.js +427 -402
- package/backend/src/core/TaskScheduler.js +82 -52
- package/backend/src/core/utils/settingsMerger.js +25 -0
- package/frontend/dist/assets/{index-BpUwmzIs.js → index-BYC2UyN-.js} +1667 -1667
- package/frontend/dist/create_issue.png +0 -0
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
# История версий
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
### [1.18.1](https://github.com/blockmineJS/blockmine/compare/v1.18.0...v1.18.1) (2025-08-03)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### 🐛 Исправления
|
|
8
|
+
|
|
9
|
+
* добавлен механизм перезапуска ботов при некоторых противных ошибках ([2eb34e3](https://github.com/blockmineJS/blockmine/commit/2eb34e3e63aaa72e5fb641d7ab155baa92dbde63))
|
|
10
|
+
* копирование кода/графов и всё что дает возможность скопировать в буфер обмена, починено ([dbe4ee6](https://github.com/blockmineJS/blockmine/commit/dbe4ee6bb2e19d99cfaaef33130c27803d5988a8))
|
|
11
|
+
* мелкие фиксы крон паттерна у планировщика. больше логов для наблюдений ([c33e7c8](https://github.com/blockmineJS/blockmine/commit/c33e7c895b3daf60bcde187cf1334ab38bb71592))
|
|
12
|
+
|
|
13
|
+
## [1.18.0](https://github.com/blockmineJS/blockmine/compare/v1.17.1...v1.18.0) (2025-07-26)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### ✨ Новые возможности
|
|
17
|
+
|
|
18
|
+
* добавлена новая кнопка - "Предложить улучшение". Поможет адептам составить свой запрос ([d741881](https://github.com/blockmineJS/blockmine/commit/d7418813e53d15fcd16c0517cea033d019ed355b))
|
|
19
|
+
* добавлено глубокое объединение настроек для плагинов и улучшена установка зависимостей ([452af4b](https://github.com/blockmineJS/blockmine/commit/452af4b67325f3faebe12c136a40f77515e805c0))
|
|
20
|
+
|
|
21
|
+
### [1.17.1](https://github.com/blockmineJS/blockmine/compare/v1.17.0...v1.17.1) (2025-07-24)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### 🐛 Исправления
|
|
25
|
+
|
|
26
|
+
* добавлена синхронизация статусов ботов каждые 10 секунд и обработка события 'bot_ready' ([c9e8bcc](https://github.com/blockmineJS/blockmine/commit/c9e8bcc5f1b31a122aa05b2bb65f3b4127dfb79a))
|
|
27
|
+
* исправление ошибок со скинами. вроде ([459d65b](https://github.com/blockmineJS/blockmine/commit/459d65ba40ec18da5d9a7402992c2cd6aa73a7d2))
|
|
28
|
+
* исправление ошибок со скинами. by сахарок ([433e5c6](https://github.com/blockmineJS/blockmine/commit/433e5c6222e385cfd0ba656c78eecd67f094b0ef))
|
|
29
|
+
* уменьшены лимиты логов для ботов. так много явно не надо ([d690dcd](https://github.com/blockmineJS/blockmine/commit/d690dcd5701603d455d105a2032f9262923cf5f0))
|
|
30
|
+
|
|
4
31
|
## [1.17.0](https://github.com/blockmineJS/blockmine/compare/v1.16.3...v1.17.0) (2025-07-24)
|
|
5
32
|
|
|
6
33
|
|
package/backend/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "backend",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "src/server.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"start": "node ../backend/cli.js",
|
|
8
|
-
"dev": "cross-env NODE_ENV=development nodemon",
|
|
9
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
10
|
-
},
|
|
11
|
-
"prisma": {
|
|
12
|
-
"seed": "node prisma/seed.js"
|
|
13
|
-
},
|
|
14
|
-
"keywords": [],
|
|
15
|
-
"author": "",
|
|
16
|
-
"license": "ISC",
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"nodemon": "^3.1.2",
|
|
19
|
-
"cross-env": "^7.0.3"
|
|
20
|
-
},
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"express-validator": "^7.2.1",
|
|
23
|
-
|
|
24
|
-
"pino": "^9.7.0",
|
|
25
|
-
"pino-pretty": "^13.0.0"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "backend",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src/server.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node ../backend/cli.js",
|
|
8
|
+
"dev": "cross-env NODE_ENV=development nodemon",
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
10
|
+
},
|
|
11
|
+
"prisma": {
|
|
12
|
+
"seed": "node prisma/seed.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"nodemon": "^3.1.2",
|
|
19
|
+
"cross-env": "^7.0.3"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"express-validator": "^7.2.1",
|
|
23
|
+
|
|
24
|
+
"pino": "^9.7.0",
|
|
25
|
+
"pino-pretty": "^13.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -12,6 +12,7 @@ const { encrypt } = require('../../core/utils/crypto');
|
|
|
12
12
|
const { randomUUID } = require('crypto');
|
|
13
13
|
const eventGraphsRouter = require('./eventGraphs');
|
|
14
14
|
const pluginIdeRouter = require('./pluginIde');
|
|
15
|
+
const { deepMergeSettings } = require('../../core/utils/settingsMerger');
|
|
15
16
|
|
|
16
17
|
const multer = require('multer');
|
|
17
18
|
const archiver = require('archiver');
|
|
@@ -163,7 +164,7 @@ router.get('/state', conditionalListAuth, (req, res) => {
|
|
|
163
164
|
router.get('/:id/logs', conditionalListAuth, (req, res) => {
|
|
164
165
|
try {
|
|
165
166
|
const botId = parseInt(req.params.id, 10);
|
|
166
|
-
const { limit =
|
|
167
|
+
const { limit = 50, offset = 0 } = req.query;
|
|
167
168
|
|
|
168
169
|
const logs = botManager.getBotLogs(botId);
|
|
169
170
|
|
|
@@ -522,7 +523,7 @@ router.get('/:botId/plugins/:pluginId/settings', authorize('plugin:settings:view
|
|
|
522
523
|
}
|
|
523
524
|
}
|
|
524
525
|
|
|
525
|
-
const finalSettings =
|
|
526
|
+
const finalSettings = deepMergeSettings(defaultSettings, savedSettings);
|
|
526
527
|
res.json(finalSettings);
|
|
527
528
|
} catch (error) {
|
|
528
529
|
console.error("[API Error] /settings GET:", error);
|
|
@@ -969,7 +970,7 @@ router.get('/:id/settings/all', authorize('bot:update'), async (req, res) => {
|
|
|
969
970
|
description: plugin.description,
|
|
970
971
|
isEnabled: plugin.isEnabled,
|
|
971
972
|
manifest: manifest,
|
|
972
|
-
settings:
|
|
973
|
+
settings: deepMergeSettings(defaultSettings, savedSettings)
|
|
973
974
|
};
|
|
974
975
|
});
|
|
975
976
|
|
|
@@ -12,7 +12,8 @@ router.use(authenticate);
|
|
|
12
12
|
|
|
13
13
|
const normalizeCronPattern = (pattern) => {
|
|
14
14
|
if (typeof pattern !== 'string') return '* * * * *';
|
|
15
|
-
|
|
15
|
+
// Убираем лишние пробелы и нормализуем паттерн
|
|
16
|
+
return pattern.replace(/\*\/1/g, '*').replace(/\s+/g, ' ').trim();
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
router.get('/', authorize('task:list'), async (req, res) => {
|
|
@@ -55,6 +55,7 @@ class BotManager {
|
|
|
55
55
|
|
|
56
56
|
getInstanceId();
|
|
57
57
|
setInterval(() => this.updateAllResourceUsage(), 5000);
|
|
58
|
+
setInterval(() => this.syncBotStatuses(), 10000);
|
|
58
59
|
if (config.telemetry?.enabled) {
|
|
59
60
|
setInterval(() => this.sendHeartbeat(), 5 * 60 * 1000);
|
|
60
61
|
}
|
|
@@ -322,6 +323,14 @@ class BotManager {
|
|
|
322
323
|
if (message) this.appendLog(botId, `[SYSTEM] ${message}`);
|
|
323
324
|
getIO().emit('bot:status', { botId, status, message });
|
|
324
325
|
}
|
|
326
|
+
|
|
327
|
+
syncBotStatuses() {
|
|
328
|
+
for (const [botId, child] of this.bots.entries()) {
|
|
329
|
+
const actualStatus = child.killed ? 'stopped' : 'running';
|
|
330
|
+
const { getIO } = require('../real-time/socketHandler');
|
|
331
|
+
getIO().emit('bot:status', { botId, status: actualStatus });
|
|
332
|
+
}
|
|
333
|
+
}
|
|
325
334
|
|
|
326
335
|
appendLog(botId, logContent) {
|
|
327
336
|
const { getIO } = require('../real-time/socketHandler');
|
|
@@ -330,7 +339,7 @@ class BotManager {
|
|
|
330
339
|
content: logContent,
|
|
331
340
|
};
|
|
332
341
|
const currentLogs = this.logCache.get(botId) || [];
|
|
333
|
-
const newLogs = [...currentLogs.slice(-
|
|
342
|
+
const newLogs = [...currentLogs.slice(-199), logEntry];
|
|
334
343
|
this.logCache.set(botId, newLogs);
|
|
335
344
|
getIO().emit('bot:log', { botId, log: logEntry });
|
|
336
345
|
}
|
|
@@ -380,7 +389,6 @@ class BotManager {
|
|
|
380
389
|
if (decryptedConfig.password) decryptedConfig.password = decrypt(decryptedConfig.password);
|
|
381
390
|
if (decryptedConfig.proxyPassword) decryptedConfig.proxyPassword = decrypt(decryptedConfig.proxyPassword);
|
|
382
391
|
|
|
383
|
-
// Очищаем данные прокси от лишних символов
|
|
384
392
|
if (decryptedConfig.proxyUsername) decryptedConfig.proxyUsername = decryptedConfig.proxyUsername.trim();
|
|
385
393
|
if (decryptedConfig.proxyPassword) decryptedConfig.proxyPassword = decryptedConfig.proxyPassword.trim();
|
|
386
394
|
|
|
@@ -431,6 +439,9 @@ class BotManager {
|
|
|
431
439
|
case 'status':
|
|
432
440
|
this.emitStatusUpdate(botId, message.status);
|
|
433
441
|
break;
|
|
442
|
+
case 'bot_ready':
|
|
443
|
+
this.emitStatusUpdate(botId, 'running', 'Бот успешно подключился к серверу.');
|
|
444
|
+
break;
|
|
434
445
|
case 'validate_and_run_command':
|
|
435
446
|
await this.handleCommandValidation(botConfig, message);
|
|
436
447
|
break;
|
|
@@ -517,8 +528,18 @@ class BotManager {
|
|
|
517
528
|
this.bots.delete(botId);
|
|
518
529
|
this.resourceUsage.delete(botId);
|
|
519
530
|
this.botConfigs.delete(botId);
|
|
531
|
+
|
|
520
532
|
this.emitStatusUpdate(botId, 'stopped', `Процесс завершился с кодом ${code} (сигнал: ${signal || 'none'}).`);
|
|
521
533
|
this.updateAllResourceUsage();
|
|
534
|
+
|
|
535
|
+
if (code === 1) {
|
|
536
|
+
console.log(`[BotManager] Обнаружена ошибка с кодом 1 для бота ${botId}. Попытка перезапуска через 5 секунд...`);
|
|
537
|
+
this.appendLog(botId, `[SYSTEM] Обнаружена критическая ошибка, перезапуск через 5 секунд...`);
|
|
538
|
+
setTimeout(() => {
|
|
539
|
+
console.log(`[BotManager] Перезапуск бота ${botId}...`);
|
|
540
|
+
this.startBot(botConfig);
|
|
541
|
+
}, 5000);
|
|
542
|
+
}
|
|
522
543
|
});
|
|
523
544
|
|
|
524
545
|
this.bots.set(botConfig.id, child);
|
|
@@ -22,6 +22,17 @@ const pendingRequests = new Map();
|
|
|
22
22
|
const entityMoveThrottles = new Map();
|
|
23
23
|
let connectionTimeout = null;
|
|
24
24
|
|
|
25
|
+
const originalJSONParse = JSON.parse
|
|
26
|
+
JSON.parse = function(text, reviver) {
|
|
27
|
+
if (typeof text !== 'string') return originalJSONParse(text, reviver)
|
|
28
|
+
try {
|
|
29
|
+
return originalJSONParse(text, reviver)
|
|
30
|
+
} catch (e) {
|
|
31
|
+
const fixed = text.replace(/([{,])\s*([a-zA-Z0-9_]+)\s*:/g, '$1"$2":')
|
|
32
|
+
return originalJSONParse(fixed, reviver)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
function sendLog(content) {
|
|
26
37
|
if (process.send) {
|
|
27
38
|
process.send({ type: 'log', content });
|
|
@@ -616,8 +627,11 @@ process.on('message', async (message) => {
|
|
|
616
627
|
clearTimeout(connectionTimeout);
|
|
617
628
|
connectionTimeout = null;
|
|
618
629
|
}
|
|
630
|
+
const restartableReasons = ['socketClosed', 'keepAliveError'];
|
|
631
|
+
const exitCode = restartableReasons.includes(reason) ? 1 : 0;
|
|
632
|
+
|
|
619
633
|
sendLog(`[Event: end] Отключен от сервера. Причина: ${reason}`);
|
|
620
|
-
process.exit(
|
|
634
|
+
process.exit(exitCode);
|
|
621
635
|
});
|
|
622
636
|
|
|
623
637
|
bot.on('playerJoined', (player) => {
|
|
@@ -1,132 +1,87 @@
|
|
|
1
|
-
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const fs = require('fs/promises');
|
|
4
|
-
const { execSync } = require('child_process');
|
|
5
|
-
const fssync = require('fs');
|
|
6
|
-
const PluginStore = require('../plugins/PluginStore');
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
pluginModule.onLoad(bot, { settings: finalSettings, store });
|
|
88
|
-
} else {
|
|
89
|
-
sendLog(`[PluginLoader] [ERROR] ${plugin.name} не экспортирует функцию или объект с методом onLoad.`);
|
|
90
|
-
}
|
|
91
|
-
} catch (error) {
|
|
92
|
-
if (error.message.includes('Cannot find module')) {
|
|
93
|
-
const moduleMatch = error.message.match(/Cannot find module '([^']+)'/);
|
|
94
|
-
if (moduleMatch) {
|
|
95
|
-
const missingModule = moduleMatch[1];
|
|
96
|
-
sendLog(`[PluginLoader] Попытка установки недостающего модуля ${missingModule} в папку плагина ${plugin.name}`);
|
|
97
|
-
const shell = process.platform === 'win32' ? process.env.ComSpec : '/bin/sh';
|
|
98
|
-
try {
|
|
99
|
-
execSync(`npm install ${missingModule}`, {
|
|
100
|
-
cwd: plugin.path,
|
|
101
|
-
stdio: 'pipe',
|
|
102
|
-
shell: shell
|
|
103
|
-
});
|
|
104
|
-
sendLog(`[PluginLoader] Модуль ${missingModule} успешно установлен в папку плагина ${plugin.name}, повторная попытка загрузки`);
|
|
105
|
-
|
|
106
|
-
// Повторная попытка загрузки
|
|
107
|
-
const pluginModule = require(normalizedPath);
|
|
108
|
-
if (typeof pluginModule === 'function') {
|
|
109
|
-
pluginModule(bot, { settings: finalSettings, store });
|
|
110
|
-
} else if (pluginModule && typeof pluginModule.onLoad === 'function') {
|
|
111
|
-
pluginModule.onLoad(bot, { settings: finalSettings, store });
|
|
112
|
-
}
|
|
113
|
-
} catch (installError) {
|
|
114
|
-
sendLog(`[PluginLoader] Не удалось установить модуль ${missingModule} в папку плагина ${plugin.name}: ${installError.message}`);
|
|
115
|
-
throw error; // Пробрасываем оригинальную ошибку
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
throw error;
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
throw error;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
} catch (error) {
|
|
126
|
-
sendLog(`[PluginLoader] [FATAL] Не удалось загрузить плагин ${plugin.name}: ${error.stack}`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
1
|
+
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs/promises');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const fssync = require('fs');
|
|
6
|
+
const PluginStore = require('../plugins/PluginStore');
|
|
7
|
+
const { deepMergeSettings } = require('./utils/settingsMerger');
|
|
8
|
+
|
|
9
|
+
const projectRoot = path.resolve(__dirname, '..');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async function initializePlugins(bot, installedPlugins = [], prisma) {
|
|
14
|
+
if (!installedPlugins || installedPlugins.length === 0) return;
|
|
15
|
+
|
|
16
|
+
const sendLog = bot.sendLog || console.log;
|
|
17
|
+
sendLog(`[PluginLoader] Загрузка ${installedPlugins.length} плагинов...`);
|
|
18
|
+
|
|
19
|
+
for (const plugin of installedPlugins) {
|
|
20
|
+
if (plugin && plugin.path) {
|
|
21
|
+
try {
|
|
22
|
+
const manifest = plugin.manifest ? JSON.parse(plugin.manifest) : {};
|
|
23
|
+
const savedSettings = plugin.settings ? JSON.parse(plugin.settings) : {};
|
|
24
|
+
const defaultSettings = {};
|
|
25
|
+
|
|
26
|
+
if (manifest.settings) {
|
|
27
|
+
for (const key in manifest.settings) {
|
|
28
|
+
const config = manifest.settings[key];
|
|
29
|
+
if (config.type === 'json_file' && config.defaultPath) {
|
|
30
|
+
const configFilePath = path.join(plugin.path, config.defaultPath);
|
|
31
|
+
try {
|
|
32
|
+
const fileContent = await fs.readFile(configFilePath, 'utf-8');
|
|
33
|
+
defaultSettings[key] = JSON.parse(fileContent);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
sendLog(`[PluginLoader] WARN: Не удалось прочитать defaultPath '${config.defaultPath}' для плагина ${plugin.name}.`);
|
|
36
|
+
defaultSettings[key] = (config.type === 'string[]' || config.type === 'json_file') ? [] : {};
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
try {
|
|
40
|
+
defaultSettings[key] = JSON.parse(config.default || 'null');
|
|
41
|
+
} catch {
|
|
42
|
+
defaultSettings[key] = config.default;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const finalSettings = deepMergeSettings(defaultSettings, savedSettings);
|
|
49
|
+
const store = new PluginStore(prisma, bot.config.id, plugin.name);
|
|
50
|
+
|
|
51
|
+
const mainFile = manifest.main || 'index.js';
|
|
52
|
+
const entryPointPath = path.join(plugin.path, mainFile);
|
|
53
|
+
const normalizedPath = entryPointPath.replace(/\\/g, '/');
|
|
54
|
+
|
|
55
|
+
sendLog(`[PluginLoader] Загрузка: ${plugin.name} (v${plugin.version}) из ${normalizedPath}`);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const pluginModule = require(normalizedPath);
|
|
59
|
+
|
|
60
|
+
if (typeof pluginModule === 'function') {
|
|
61
|
+
pluginModule(bot, { settings: finalSettings, store });
|
|
62
|
+
} else if (pluginModule && typeof pluginModule.onLoad === 'function') {
|
|
63
|
+
pluginModule.onLoad(bot, { settings: finalSettings, store });
|
|
64
|
+
} else {
|
|
65
|
+
sendLog(`[PluginLoader] [ERROR] ${plugin.name} не экспортирует функцию или объект с методом onLoad.`);
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// Зависимости должны быть установлены заранее в PluginManager
|
|
69
|
+
// Если модуль не найден, это означает, что установка зависимостей не была выполнена корректно
|
|
70
|
+
if (error.message.includes('Cannot find module')) {
|
|
71
|
+
const moduleMatch = error.message.match(/Cannot find module '([^']+)'/);
|
|
72
|
+
if (moduleMatch) {
|
|
73
|
+
const missingModule = moduleMatch[1];
|
|
74
|
+
sendLog(`[PluginLoader] [ERROR] Модуль ${missingModule} не найден для плагина ${plugin.name}. Зависимости должны быть установлены заранее.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
} catch (error) {
|
|
81
|
+
sendLog(`[PluginLoader] [FATAL] Не удалось загрузить плагин ${plugin.name}: ${error.stack}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
132
87
|
module.exports = { initializePlugins };
|