blockmine 1.6.3 → 1.13.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/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.versionrc.json +17 -0
- package/CHANGELOG.md +36 -0
- package/README.md +1 -1
- package/backend/package.json +1 -0
- package/backend/prisma/migrations/20250718181335_add_plugin_data_store/migration.sql +14 -0
- package/backend/prisma/schema.prisma +17 -2
- package/backend/src/api/routes/auth.js +140 -0
- package/backend/src/api/routes/bots.js +176 -0
- package/backend/src/api/routes/changelog.js +16 -0
- package/backend/src/api/routes/eventGraphs.js +11 -1
- package/backend/src/api/routes/plugins.js +11 -0
- package/backend/src/core/BotManager.js +92 -40
- package/backend/src/core/BotProcess.js +44 -24
- package/backend/src/core/EventGraphManager.js +29 -5
- package/backend/src/core/GraphExecutionEngine.js +54 -12
- package/backend/src/core/MessageQueue.js +10 -1
- package/backend/src/core/NodeRegistry.js +2 -1
- package/backend/src/core/PluginLoader.js +72 -8
- package/backend/src/core/PluginManager.js +19 -0
- package/backend/src/plugins/PluginStore.js +87 -0
- package/backend/src/real-time/socketHandler.js +11 -3
- package/backend/src/server.js +2 -0
- package/backend/temp_migration.sql +0 -0
- package/commitlint.config.js +3 -0
- package/frontend/dist/assets/index-CHwi1QN9.js +8331 -0
- package/frontend/dist/assets/index-DhU2u6V0.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +6 -0
- package/package.json +20 -4
- package/frontend/dist/assets/index-CIDmlKtb.js +0 -8203
- package/frontend/dist/assets/index-DF3i-W3m.css +0 -1
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs/promises');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const fssync = require('fs');
|
|
6
|
+
const PluginStore = require('../plugins/PluginStore');
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
const projectRoot = path.resolve(__dirname, '..');
|
|
9
|
+
|
|
10
|
+
async function ensurePluginDependencies(pluginPath, pluginName) {
|
|
11
|
+
const packageJsonPath = path.join(pluginPath, 'package.json');
|
|
12
|
+
try {
|
|
13
|
+
if (fssync.existsSync(packageJsonPath)) {
|
|
14
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
|
|
15
|
+
if (packageJson.dependencies && Object.keys(packageJson.dependencies).length > 0) {
|
|
16
|
+
console.log(`[PluginLoader] У плагина ${pluginName} есть зависимости, устанавливаем их...`);
|
|
17
|
+
try {
|
|
18
|
+
execSync('npm install', {
|
|
19
|
+
cwd: pluginPath,
|
|
20
|
+
stdio: 'pipe'
|
|
21
|
+
});
|
|
22
|
+
console.log(`[PluginLoader] Зависимости для плагина ${pluginName} установлены`);
|
|
23
|
+
} catch (installError) {
|
|
24
|
+
console.error(`[PluginLoader] Ошибка установки зависимостей для ${pluginName}:`, installError.message);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(`[PluginLoader] Ошибка чтения package.json для ${pluginName}:`, error.message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function initializePlugins(bot, installedPlugins = [], prisma) {
|
|
6
34
|
if (!installedPlugins || installedPlugins.length === 0) return;
|
|
7
35
|
|
|
8
36
|
const sendLog = bot.sendLog || console.log;
|
|
@@ -11,6 +39,8 @@ async function initializePlugins(bot, installedPlugins = []) {
|
|
|
11
39
|
for (const plugin of installedPlugins) {
|
|
12
40
|
if (plugin && plugin.path) {
|
|
13
41
|
try {
|
|
42
|
+
await ensurePluginDependencies(plugin.path, plugin.name);
|
|
43
|
+
|
|
14
44
|
const manifest = plugin.manifest ? JSON.parse(plugin.manifest) : {};
|
|
15
45
|
const savedSettings = plugin.settings ? JSON.parse(plugin.settings) : {};
|
|
16
46
|
const defaultSettings = {};
|
|
@@ -38,20 +68,54 @@ async function initializePlugins(bot, installedPlugins = []) {
|
|
|
38
68
|
}
|
|
39
69
|
|
|
40
70
|
const finalSettings = { ...defaultSettings, ...savedSettings };
|
|
71
|
+
const store = new PluginStore(prisma, bot.config.id, plugin.name);
|
|
41
72
|
|
|
42
73
|
const mainFile = manifest.main || 'index.js';
|
|
43
74
|
const entryPointPath = path.join(plugin.path, mainFile);
|
|
44
75
|
const normalizedPath = entryPointPath.replace(/\\/g, '/');
|
|
45
76
|
|
|
46
77
|
sendLog(`[PluginLoader] Загрузка: ${plugin.name} (v${plugin.version}) из ${normalizedPath}`);
|
|
47
|
-
const pluginModule = require(normalizedPath);
|
|
48
78
|
|
|
49
|
-
|
|
50
|
-
pluginModule
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
79
|
+
try {
|
|
80
|
+
const pluginModule = require(normalizedPath);
|
|
81
|
+
|
|
82
|
+
if (typeof pluginModule === 'function') {
|
|
83
|
+
pluginModule(bot, { settings: finalSettings, store });
|
|
84
|
+
} else if (pluginModule && typeof pluginModule.onLoad === 'function') {
|
|
85
|
+
pluginModule.onLoad(bot, { settings: finalSettings, store });
|
|
86
|
+
} else {
|
|
87
|
+
sendLog(`[PluginLoader] [ERROR] ${plugin.name} не экспортирует функцию или объект с методом onLoad.`);
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (error.message.includes('Cannot find module')) {
|
|
91
|
+
const moduleMatch = error.message.match(/Cannot find module '([^']+)'/);
|
|
92
|
+
if (moduleMatch) {
|
|
93
|
+
const missingModule = moduleMatch[1];
|
|
94
|
+
sendLog(`[PluginLoader] Попытка установки недостающего модуля ${missingModule} в папку плагина ${plugin.name}`);
|
|
95
|
+
try {
|
|
96
|
+
execSync(`npm install ${missingModule}`, {
|
|
97
|
+
cwd: plugin.path,
|
|
98
|
+
stdio: 'pipe'
|
|
99
|
+
});
|
|
100
|
+
sendLog(`[PluginLoader] Модуль ${missingModule} успешно установлен в папку плагина ${plugin.name}, повторная попытка загрузки`);
|
|
101
|
+
|
|
102
|
+
// Повторная попытка загрузки
|
|
103
|
+
const pluginModule = require(normalizedPath);
|
|
104
|
+
if (typeof pluginModule === 'function') {
|
|
105
|
+
pluginModule(bot, { settings: finalSettings, store });
|
|
106
|
+
} else if (pluginModule && typeof pluginModule.onLoad === 'function') {
|
|
107
|
+
pluginModule.onLoad(bot, { settings: finalSettings, store });
|
|
108
|
+
}
|
|
109
|
+
} catch (installError) {
|
|
110
|
+
sendLog(`[PluginLoader] Не удалось установить модуль ${missingModule} в папку плагина ${plugin.name}: ${installError.message}`);
|
|
111
|
+
throw error; // Пробрасываем оригинальную ошибку
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
55
119
|
}
|
|
56
120
|
|
|
57
121
|
} catch (error) {
|
|
@@ -277,6 +277,25 @@ class PluginManager {
|
|
|
277
277
|
|
|
278
278
|
return await this.installFromGithub(botId, repoUrl, prisma, true);
|
|
279
279
|
}
|
|
280
|
+
|
|
281
|
+
async clearPluginData(pluginId) {
|
|
282
|
+
const plugin = await prisma.installedPlugin.findUnique({ where: { id: pluginId } });
|
|
283
|
+
if (!plugin) {
|
|
284
|
+
throw new Error('Плагин не найден.');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
console.log(`[PluginManager] Очистка данных для плагина ${plugin.name} (Bot ID: ${plugin.botId})`);
|
|
288
|
+
|
|
289
|
+
const { count } = await prisma.pluginDataStore.deleteMany({
|
|
290
|
+
where: {
|
|
291
|
+
pluginName: plugin.name,
|
|
292
|
+
botId: plugin.botId,
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
console.log(`[PluginManager] Удалено ${count} записей из хранилища.`);
|
|
297
|
+
return { count };
|
|
298
|
+
}
|
|
280
299
|
}
|
|
281
300
|
|
|
282
301
|
module.exports = PluginManager;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
class PluginStore {
|
|
2
|
+
constructor(prisma, botId, pluginName) {
|
|
3
|
+
this.prisma = prisma;
|
|
4
|
+
this.botId = botId;
|
|
5
|
+
this.pluginName = pluginName;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async set(key, value) {
|
|
9
|
+
const jsonValue = JSON.stringify(value);
|
|
10
|
+
await this.prisma.pluginDataStore.upsert({
|
|
11
|
+
where: {
|
|
12
|
+
pluginName_botId_key: {
|
|
13
|
+
pluginName: this.pluginName,
|
|
14
|
+
botId: this.botId,
|
|
15
|
+
key: key
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
update: {
|
|
19
|
+
value: jsonValue
|
|
20
|
+
},
|
|
21
|
+
create: {
|
|
22
|
+
pluginName: this.pluginName,
|
|
23
|
+
botId: this.botId,
|
|
24
|
+
key: key,
|
|
25
|
+
value: jsonValue
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async get(key) {
|
|
31
|
+
const data = await this.prisma.pluginDataStore.findUnique({
|
|
32
|
+
where: {
|
|
33
|
+
pluginName_botId_key: {
|
|
34
|
+
pluginName: this.pluginName,
|
|
35
|
+
botId: this.botId,
|
|
36
|
+
key: key
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
return data ? JSON.parse(data.value) : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async delete(key) {
|
|
44
|
+
try {
|
|
45
|
+
await this.prisma.pluginDataStore.delete({
|
|
46
|
+
where: {
|
|
47
|
+
pluginName_botId_key: {
|
|
48
|
+
pluginName: this.pluginName,
|
|
49
|
+
botId: this.botId,
|
|
50
|
+
key: key
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return true;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async has(key) {
|
|
61
|
+
const count = await this.prisma.pluginDataStore.count({
|
|
62
|
+
where: {
|
|
63
|
+
pluginName: this.pluginName,
|
|
64
|
+
botId: this.botId,
|
|
65
|
+
key: key
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return count > 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async getAll() {
|
|
72
|
+
const allData = await this.prisma.pluginDataStore.findMany({
|
|
73
|
+
where: {
|
|
74
|
+
pluginName: this.pluginName,
|
|
75
|
+
botId: this.botId
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
const map = new Map();
|
|
79
|
+
for (const item of allData) {
|
|
80
|
+
map.set(item.key, JSON.parse(item.value));
|
|
81
|
+
}
|
|
82
|
+
return map;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = PluginStore;
|
|
87
|
+
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const { Server } = require('socket.io');
|
|
2
2
|
const config = require('../config');
|
|
3
3
|
|
|
4
|
+
const { botManager } = require('../core/services');
|
|
5
|
+
|
|
4
6
|
let io;
|
|
5
7
|
|
|
6
8
|
function initializeSocket(httpServer) {
|
|
@@ -16,14 +18,20 @@ function initializeSocket(httpServer) {
|
|
|
16
18
|
});
|
|
17
19
|
|
|
18
20
|
io.on('connection', (socket) => {
|
|
19
|
-
// console.log(`[Socket.IO] Пользователь подключен: ${socket.id}. Всего клиентов: ${io.engine.clientsCount}`);
|
|
20
21
|
|
|
21
22
|
socket.on('disconnect', () => {
|
|
22
|
-
|
|
23
|
+
botManager.handleSocketDisconnect(socket);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
socket.on('plugin:ui:subscribe', ({ botId, pluginName }) => {
|
|
27
|
+
botManager.subscribeToPluginUi(botId, pluginName, socket);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
socket.on('plugin:ui:unsubscribe', ({ botId, pluginName }) => {
|
|
31
|
+
botManager.unsubscribeFromPluginUi(botId, pluginName, socket);
|
|
23
32
|
});
|
|
24
33
|
});
|
|
25
34
|
|
|
26
|
-
// console.log('Socket.IO инициализирован с динамическим CORS.');
|
|
27
35
|
return io;
|
|
28
36
|
}
|
|
29
37
|
|
package/backend/src/server.js
CHANGED
|
@@ -19,6 +19,7 @@ const searchRoutes = require('./api/routes/search');
|
|
|
19
19
|
const eventGraphsRouter = require('./api/routes/eventGraphs');
|
|
20
20
|
const TaskScheduler = require('./core/TaskScheduler');
|
|
21
21
|
const panelRoutes = require('./api/routes/panel');
|
|
22
|
+
const changelogRoutes = require('./api/routes/changelog');
|
|
22
23
|
|
|
23
24
|
const app = express();
|
|
24
25
|
const server = http.createServer(app);
|
|
@@ -59,6 +60,7 @@ app.use('/api/servers', serverRoutes);
|
|
|
59
60
|
app.use('/api/permissions', permissionsRoutes);
|
|
60
61
|
app.use('/api/search', searchRoutes);
|
|
61
62
|
app.use('/api/panel', panelRoutes);
|
|
63
|
+
app.use('/api/changelog', changelogRoutes);
|
|
62
64
|
|
|
63
65
|
app.use(express.static(frontendPath));
|
|
64
66
|
|
|
Binary file
|