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.
@@ -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; }
@@ -149,6 +149,9 @@ class EventGraphManager {
149
149
  case 'playerLeft':
150
150
  context.user = args.user;
151
151
  break;
152
+ case 'botDied':
153
+ context.user = args.user;
154
+ break;
152
155
  case 'tick':
153
156
  break;
154
157
  case 'entitySpawn':
@@ -536,18 +536,27 @@ class GraphExecutionEngine {
536
536
  }
537
537
 
538
538
  case 'string:contains': {
539
- const haystack = String(await this.resolvePinValue(node, 'haystack', ''));
540
- const needle = String(await this.resolvePinValue(node, 'needle', ''));
541
- const caseSensitive = await this.resolvePinValue(node, 'case_sensitive', true);
542
- result = caseSensitive ? haystack.includes(needle) : haystack.toLowerCase().includes(needle.toLowerCase());
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
- const str = String(await this.resolvePinValue(node, 'input', ''));
547
- const regexStr = String(await this.resolvePinValue(node, 'regex', ''));
548
- try {
549
- result = new RegExp(regexStr).test(str);
550
- } catch (e) { result = false; }
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.sourceType === 'GITHUB' || plugin.sourceType === 'IMPORTED') {
212
+ if (plugin.path && plugin.path.startsWith(PLUGINS_BASE_DIR)) {
213
213
  try {
214
- await fse.remove(plugin.path);
215
- console.log(`[PluginManager] Папка плагина ${plugin.path} успешно удалена.`);
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 { PrismaClient } = require('@prisma/client');
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();
@@ -0,0 +1,5 @@
1
+ const { PrismaClient } = require('@prisma/client');
2
+
3
+ const prisma = new PrismaClient();
4
+
5
+ module.exports = prisma;
@@ -5,27 +5,25 @@ let io;
5
5
 
6
6
  function initializeSocket(httpServer) {
7
7
  const corsOptions = {
8
- methods: ["GET", "POST"]
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('Socket.IO: Пользователь подключен -', socket.id);
19
+ // console.log(`[Socket.IO] Пользователь подключен: ${socket.id}. Всего клиентов: ${io.engine.clientsCount}`);
20
+
23
21
  socket.on('disconnect', () => {
24
- console.log('Socket.IO: Пользователь отключен -', socket.id);
22
+ // console.log(`[Socket.IO] Пользователь отключен: ${socket.id}. Всего клиентов: ${io.engine.clientsCount}`);
25
23
  });
26
24
  });
27
25
 
28
- console.log('Socket.IO инициализирован с CORS для:', corsOptions.origin);
26
+ // console.log('Socket.IO инициализирован с динамическим CORS.');
29
27
  return io;
30
28
  }
31
29
 
@@ -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
- const gracefulShutdown = (signal) => {
110
- console.log(`[Shutdown] Получен сигнал ${signal}. Начинаем завершение...`);
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
- for (const botId of botIds) {
116
- botManager.stopBot(botId);
117
- }
153
+ await Promise.all(botIds.map(botId => botManager.stopBot(botId)));
154
+ console.log('[Shutdown] Все боты остановлены.');
118
155
  }
119
156
 
120
- server.close(() => {
121
- console.log('[Shutdown] HTTP сервер закрыт. Завершение процесса.');
122
- process.exit(0);
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
- setTimeout(() => {
126
- console.error('[Shutdown] Не удалось закрыть соединения вовремя, принудительное завершение.');
127
- process.exit(1);
128
- }, 5000);
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)'));