blockmine 1.5.5 → 1.5.9
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/README.md +2 -3
- package/backend/src/api/routes/auth.js +10 -3
- package/backend/src/api/routes/bots.js +20 -11
- package/backend/src/api/routes/pluginIde.js +463 -0
- package/backend/src/api/routes/plugins.js +4 -6
- package/backend/src/core/BotManager.js +707 -714
- package/backend/src/core/BotProcess.js +5 -0
- package/backend/src/core/EventGraphManager.js +3 -0
- package/backend/src/core/GraphExecutionEngine.js +18 -9
- package/backend/src/core/NodeRegistry.js +14 -0
- package/backend/src/core/PluginManager.js +7 -3
- package/backend/src/core/TaskScheduler.js +8 -3
- package/backend/src/lib/prisma.js +5 -0
- package/backend/src/real-time/socketHandler.js +9 -11
- package/backend/src/server.js +63 -19
- package/frontend/dist/assets/index-Cb7r5FoV.js +8203 -0
- package/frontend/dist/assets/index-OIucIMTn.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +2 -0
- package/package.json +4 -1
- package/frontend/dist/assets/index-BSQ59n1K.js +0 -8203
- package/frontend/dist/assets/index-DC4RjP6E.css +0 -1
|
@@ -160,6 +160,7 @@ process.on('message', async (message) => {
|
|
|
160
160
|
version: config.server.version,
|
|
161
161
|
auth: 'offline',
|
|
162
162
|
hideErrors: false,
|
|
163
|
+
chat: 'enabled',
|
|
163
164
|
};
|
|
164
165
|
|
|
165
166
|
if (config.proxyHost && config.proxyPort) {
|
|
@@ -484,6 +485,10 @@ process.on('message', async (message) => {
|
|
|
484
485
|
}
|
|
485
486
|
});
|
|
486
487
|
|
|
488
|
+
bot.on('death', () => {
|
|
489
|
+
sendEvent('botDied', { user: { username: bot.username } });
|
|
490
|
+
});
|
|
491
|
+
|
|
487
492
|
bot.on('kicked', (reason) => {
|
|
488
493
|
let reasonText;
|
|
489
494
|
try { reasonText = JSON.parse(reason).text || reason; } catch (e) { reasonText = reason; }
|
|
@@ -536,18 +536,27 @@ class GraphExecutionEngine {
|
|
|
536
536
|
}
|
|
537
537
|
|
|
538
538
|
case 'string:contains': {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
539
|
+
if (pinId === 'result') {
|
|
540
|
+
const haystack = String(await this.resolvePinValue(node, 'haystack', ''));
|
|
541
|
+
const needle = String(await this.resolvePinValue(node, 'needle', ''));
|
|
542
|
+
const caseSensitive = await this.resolvePinValue(node, 'case_sensitive', false);
|
|
543
|
+
|
|
544
|
+
if (caseSensitive) {
|
|
545
|
+
return haystack.includes(needle);
|
|
546
|
+
} else {
|
|
547
|
+
return haystack.toLowerCase().includes(needle.toLowerCase());
|
|
548
|
+
}
|
|
549
|
+
}
|
|
543
550
|
break;
|
|
544
551
|
}
|
|
545
552
|
case 'string:matches': {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
553
|
+
if (pinId === 'result') {
|
|
554
|
+
const str = String(await this.resolvePinValue(node, 'string', ''));
|
|
555
|
+
const regexStr = String(await this.resolvePinValue(node, 'regex', ''));
|
|
556
|
+
try {
|
|
557
|
+
result = new RegExp(regexStr).test(str);
|
|
558
|
+
} catch (e) { result = false; }
|
|
559
|
+
}
|
|
551
560
|
break;
|
|
552
561
|
}
|
|
553
562
|
case 'data:string_literal':
|
|
@@ -876,6 +876,20 @@ class NodeRegistry {
|
|
|
876
876
|
}
|
|
877
877
|
});
|
|
878
878
|
|
|
879
|
+
this.registerNodeType({
|
|
880
|
+
type: 'event:botDied',
|
|
881
|
+
label: '💀 Бот умер',
|
|
882
|
+
category: 'События',
|
|
883
|
+
description: 'Срабатывает, когда бот умирает.',
|
|
884
|
+
graphType: event,
|
|
885
|
+
pins: {
|
|
886
|
+
inputs: [],
|
|
887
|
+
outputs: [
|
|
888
|
+
{ id: 'exec', name: 'Выполнить', type: 'Exec' },
|
|
889
|
+
]
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
|
|
879
893
|
console.log(`NodeRegistry: Registered ${this.nodes.size} base nodes`);
|
|
880
894
|
}
|
|
881
895
|
|
|
@@ -209,10 +209,14 @@ class PluginManager {
|
|
|
209
209
|
throw new Error('Ошибка при удалении данных плагина из БД. Файлы не были удалены.');
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
if (plugin.
|
|
212
|
+
if (plugin.path && plugin.path.startsWith(PLUGINS_BASE_DIR)) {
|
|
213
213
|
try {
|
|
214
|
-
await fse.
|
|
215
|
-
|
|
214
|
+
if (await fse.pathExists(plugin.path)) {
|
|
215
|
+
await fse.remove(plugin.path);
|
|
216
|
+
console.log(`[PluginManager] Папка плагина ${plugin.path} успешно удалена.`);
|
|
217
|
+
} else {
|
|
218
|
+
console.log(`[PluginManager] Папка плагина ${plugin.path} не найдена, удаление не требуется.`);
|
|
219
|
+
}
|
|
216
220
|
} catch (fileError) {
|
|
217
221
|
console.error(`Не удалось удалить папку плагина ${plugin.path}:`, fileError);
|
|
218
222
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
const cron = require('node-cron');
|
|
2
|
-
const
|
|
2
|
+
const prisma = require('../lib/prisma');
|
|
3
3
|
const BotManager = require('./BotManager');
|
|
4
4
|
|
|
5
|
-
const prisma = new PrismaClient();
|
|
6
|
-
|
|
7
5
|
class TaskScheduler {
|
|
8
6
|
constructor() {
|
|
9
7
|
this.scheduledJobs = new Map();
|
|
@@ -112,6 +110,13 @@ class TaskScheduler {
|
|
|
112
110
|
this.scheduleTask(updatedTask);
|
|
113
111
|
}
|
|
114
112
|
}
|
|
113
|
+
|
|
114
|
+
shutdown() {
|
|
115
|
+
console.log('[TaskScheduler] Остановка всех запланированных задач...');
|
|
116
|
+
this.scheduledJobs.forEach(job => job.stop());
|
|
117
|
+
this.scheduledJobs.clear();
|
|
118
|
+
console.log('[TaskScheduler] Все задачи остановлены.');
|
|
119
|
+
}
|
|
115
120
|
}
|
|
116
121
|
|
|
117
122
|
module.exports = new TaskScheduler();
|
|
@@ -5,27 +5,25 @@ let io;
|
|
|
5
5
|
|
|
6
6
|
function initializeSocket(httpServer) {
|
|
7
7
|
const corsOptions = {
|
|
8
|
-
|
|
8
|
+
origin: true,
|
|
9
|
+
methods: ["GET", "POST"],
|
|
10
|
+
credentials: true
|
|
9
11
|
};
|
|
10
12
|
|
|
11
|
-
if (config.server.allowExternalAccess) {
|
|
12
|
-
corsOptions.origin = "*";
|
|
13
|
-
} else {
|
|
14
|
-
corsOptions.origin = "http://localhost:5173";
|
|
15
|
-
}
|
|
16
|
-
|
|
17
13
|
io = new Server(httpServer, {
|
|
18
|
-
cors: corsOptions
|
|
14
|
+
cors: corsOptions,
|
|
15
|
+
transports: ['websocket', 'polling']
|
|
19
16
|
});
|
|
20
17
|
|
|
21
18
|
io.on('connection', (socket) => {
|
|
22
|
-
console.log(
|
|
19
|
+
// console.log(`[Socket.IO] Пользователь подключен: ${socket.id}. Всего клиентов: ${io.engine.clientsCount}`);
|
|
20
|
+
|
|
23
21
|
socket.on('disconnect', () => {
|
|
24
|
-
console.log(
|
|
22
|
+
// console.log(`[Socket.IO] Пользователь отключен: ${socket.id}. Всего клиентов: ${io.engine.clientsCount}`);
|
|
25
23
|
});
|
|
26
24
|
});
|
|
27
25
|
|
|
28
|
-
console.log('Socket.IO инициализирован с CORS
|
|
26
|
+
// console.log('Socket.IO инициализирован с динамическим CORS.');
|
|
29
27
|
return io;
|
|
30
28
|
}
|
|
31
29
|
|
package/backend/src/server.js
CHANGED
|
@@ -3,25 +3,23 @@ const http = require('http');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const os = require('os');
|
|
6
|
+
const prisma = require('./lib/prisma');
|
|
6
7
|
|
|
7
|
-
const config = require('./config');
|
|
8
|
+
const config = require('./config');
|
|
8
9
|
const { initializeSocket } = require('./real-time/socketHandler');
|
|
9
10
|
const { botManager, pluginManager } = require('./core/services');
|
|
10
11
|
|
|
11
|
-
|
|
12
12
|
const botRoutes = require('./api/routes/bots');
|
|
13
13
|
const pluginRoutes = require('./api/routes/plugins');
|
|
14
14
|
const serverRoutes = require('./api/routes/servers');
|
|
15
15
|
const permissionsRoutes = require('./api/routes/permissions');
|
|
16
16
|
const taskRoutes = require('./api/routes/tasks');
|
|
17
|
-
const authRoutes = require('./api/routes/auth');
|
|
17
|
+
const { router: authRoutes, ALL_PERMISSIONS } = require('./api/routes/auth');
|
|
18
18
|
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
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
23
|
const app = express();
|
|
26
24
|
const server = http.createServer(app);
|
|
27
25
|
|
|
@@ -59,6 +57,7 @@ app.use('/api/bots', botRoutes);
|
|
|
59
57
|
app.use('/api/plugins', pluginRoutes);
|
|
60
58
|
app.use('/api/servers', serverRoutes);
|
|
61
59
|
app.use('/api/permissions', permissionsRoutes);
|
|
60
|
+
app.use('/api/search', searchRoutes);
|
|
62
61
|
app.use('/api/panel', panelRoutes);
|
|
63
62
|
|
|
64
63
|
app.use(express.static(frontendPath));
|
|
@@ -76,7 +75,43 @@ app.get(/^(?!\/api).*/, (req, res) => {
|
|
|
76
75
|
}
|
|
77
76
|
});
|
|
78
77
|
|
|
78
|
+
async function runStartupMigrations() {
|
|
79
|
+
try {
|
|
80
|
+
const adminRole = await prisma.panelRole.findUnique({ where: { name: 'Admin' } });
|
|
81
|
+
if (adminRole) {
|
|
82
|
+
const permissions = JSON.parse(adminRole.permissions);
|
|
83
|
+
if (permissions.includes('*')) {
|
|
84
|
+
const newPermissions = ALL_PERMISSIONS
|
|
85
|
+
.map(p => p.id)
|
|
86
|
+
.filter(id => id !== '*' && id !== 'plugin:develop');
|
|
87
|
+
|
|
88
|
+
await prisma.panelRole.update({
|
|
89
|
+
where: { id: adminRole.id },
|
|
90
|
+
data: { permissions: JSON.stringify(newPermissions) }
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const rootUser = await prisma.panelUser.findUnique({ where: { id: 1 }, include: { role: true } });
|
|
96
|
+
if (rootUser && rootUser.role) {
|
|
97
|
+
const allPermissions = ALL_PERMISSIONS.map(p => p.id).filter(id => id !== '*');
|
|
98
|
+
const currentPermissions = JSON.parse(rootUser.role.permissions);
|
|
99
|
+
|
|
100
|
+
if (JSON.stringify(allPermissions.sort()) !== JSON.stringify(currentPermissions.sort())) {
|
|
101
|
+
await prisma.panelRole.update({
|
|
102
|
+
where: { id: rootUser.role.id },
|
|
103
|
+
data: { permissions: JSON.stringify(allPermissions) }
|
|
104
|
+
});
|
|
105
|
+
console.log(`[Migration] Права для root-пользователя "${rootUser.username}" (ID: 1) были синхронизированы.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('[Migration] Ошибка во время миграции прав:', error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
79
113
|
async function startServer() {
|
|
114
|
+
await runStartupMigrations();
|
|
80
115
|
return new Promise((resolve) => {
|
|
81
116
|
server.listen(PORT, HOST, async () => {
|
|
82
117
|
console.log(`\nBackend сервер успешно запущен на http://${HOST}:${PORT}`);
|
|
@@ -106,26 +141,35 @@ async function startServer() {
|
|
|
106
141
|
});
|
|
107
142
|
}
|
|
108
143
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
144
|
+
|
|
145
|
+
const gracefulShutdown = async (signal) => {
|
|
146
|
+
console.log(`[Shutdown] Получен сигнал ${signal}. Начинаем корректное завершение...`);
|
|
147
|
+
|
|
148
|
+
TaskScheduler.shutdown();
|
|
149
|
+
|
|
112
150
|
const botIds = Array.from(botManager.bots.keys());
|
|
113
151
|
if (botIds.length > 0) {
|
|
114
152
|
console.log(`[Shutdown] Остановка ${botIds.length} активных ботов...`);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
153
|
+
await Promise.all(botIds.map(botId => botManager.stopBot(botId)));
|
|
154
|
+
console.log('[Shutdown] Все боты остановлены.');
|
|
118
155
|
}
|
|
119
156
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
157
|
+
const io = require('./real-time/socketHandler').getIO();
|
|
158
|
+
if (io) {
|
|
159
|
+
io.close(async () => {
|
|
160
|
+
console.log('[Shutdown] WebSocket сервер закрыт.');
|
|
161
|
+
|
|
162
|
+
await new Promise(resolve => server.close(resolve));
|
|
163
|
+
console.log('[Shutdown] HTTP сервер закрыт.');
|
|
124
164
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
165
|
+
const prisma = require('./lib/prisma');
|
|
166
|
+
await prisma.$disconnect();
|
|
167
|
+
console.log('[Shutdown] Соединение с БД закрыто.');
|
|
168
|
+
|
|
169
|
+
console.log('[Shutdown] Корректное завершение выполнено.');
|
|
170
|
+
process.exit(0);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
129
173
|
};
|
|
130
174
|
|
|
131
175
|
process.on('SIGUSR2', () => gracefulShutdown('SIGUSR2 (nodemon)'));
|