blockmine 1.22.0 → 1.23.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/.claude/agents/code-architect.md +34 -0
- package/.claude/agents/code-explorer.md +51 -0
- package/.claude/agents/code-reviewer.md +46 -0
- package/.claude/commands/feature-dev.md +125 -0
- package/.claude/settings.json +5 -1
- package/.claude/settings.local.json +12 -1
- package/.claude/skills/frontend-design/SKILL.md +42 -0
- package/CHANGELOG.md +32 -1
- package/README.md +302 -152
- package/backend/package-lock.json +681 -9
- package/backend/package.json +8 -0
- package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
- package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
- package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
- package/backend/prisma/schema.prisma +70 -1
- package/backend/src/__tests__/services/BotLifecycleService.test.js +9 -4
- package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
- package/backend/src/api/middleware/auth.js +27 -0
- package/backend/src/api/middleware/botAccess.js +7 -3
- package/backend/src/api/middleware/panelApiAuth.js +135 -0
- package/backend/src/api/routes/aiAssistant.js +995 -0
- package/backend/src/api/routes/auth.js +90 -54
- package/backend/src/api/routes/botCommands.js +107 -0
- package/backend/src/api/routes/botGroups.js +165 -0
- package/backend/src/api/routes/botHistory.js +108 -0
- package/backend/src/api/routes/botPermissions.js +99 -0
- package/backend/src/api/routes/botStatus.js +36 -0
- package/backend/src/api/routes/botUsers.js +162 -0
- package/backend/src/api/routes/bots.js +108 -59
- package/backend/src/api/routes/eventGraphs.js +4 -1
- package/backend/src/api/routes/logs.js +13 -3
- package/backend/src/api/routes/panel.js +3 -3
- package/backend/src/api/routes/panelApiKeys.js +179 -0
- package/backend/src/api/routes/pluginIde.js +1715 -135
- package/backend/src/api/routes/plugins.js +170 -13
- package/backend/src/api/routes/proxies.js +130 -0
- package/backend/src/api/routes/search.js +4 -0
- package/backend/src/api/routes/servers.js +20 -3
- package/backend/src/api/routes/settings.js +5 -0
- package/backend/src/api/routes/system.js +3 -3
- package/backend/src/api/routes/traces.js +131 -0
- package/backend/src/config/debug.config.js +36 -0
- package/backend/src/core/BotHistoryStore.js +180 -0
- package/backend/src/core/BotManager.js +14 -4
- package/backend/src/core/BotProcess.js +1517 -1092
- package/backend/src/core/EventGraphManager.js +194 -280
- package/backend/src/core/GraphExecutionEngine.js +1004 -321
- package/backend/src/core/MessageQueue.js +12 -6
- package/backend/src/core/PluginLoader.js +99 -5
- package/backend/src/core/PluginManager.js +74 -13
- package/backend/src/core/TaskScheduler.js +1 -1
- package/backend/src/core/commands/whois.js +1 -1
- package/backend/src/core/node-registries/actions.js +72 -2
- package/backend/src/core/node-registries/arrays.js +18 -0
- package/backend/src/core/node-registries/data.js +1 -1
- package/backend/src/core/node-registries/events.js +14 -0
- package/backend/src/core/node-registries/logic.js +17 -0
- package/backend/src/core/node-registries/strings.js +34 -0
- package/backend/src/core/node-registries/type.js +25 -0
- package/backend/src/core/nodes/actions/bot_look_at.js +1 -1
- package/backend/src/core/nodes/actions/create_command.js +189 -0
- package/backend/src/core/nodes/actions/delete_command.js +92 -0
- package/backend/src/core/nodes/actions/http_request.js +23 -4
- package/backend/src/core/nodes/actions/send_message.js +2 -12
- package/backend/src/core/nodes/actions/update_command.js +133 -0
- package/backend/src/core/nodes/arrays/join.js +28 -0
- package/backend/src/core/nodes/data/cast.js +2 -1
- package/backend/src/core/nodes/data/string_literal.js +2 -13
- package/backend/src/core/nodes/logic/not.js +22 -0
- package/backend/src/core/nodes/strings/starts_with.js +1 -1
- package/backend/src/core/nodes/strings/to_lower.js +22 -0
- package/backend/src/core/nodes/strings/to_upper.js +22 -0
- package/backend/src/core/nodes/type/to_string.js +32 -0
- package/backend/src/core/services/BotLifecycleService.js +835 -596
- package/backend/src/core/services/CommandExecutionService.js +430 -351
- package/backend/src/core/services/DebugSessionManager.js +347 -0
- package/backend/src/core/services/GraphCollaborationManager.js +501 -0
- package/backend/src/core/services/MinecraftBotManager.js +259 -0
- package/backend/src/core/services/MinecraftViewerService.js +216 -0
- package/backend/src/core/services/TraceCollectorService.js +545 -0
- package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
- package/backend/src/core/system/Transport.js +0 -4
- package/backend/src/core/validation/nodeSchemas.js +6 -6
- package/backend/src/real-time/botApi/handlers/graphHandlers.js +2 -2
- package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +1 -1
- package/backend/src/real-time/botApi/utils.js +11 -0
- package/backend/src/real-time/panelNamespace.js +387 -0
- package/backend/src/real-time/presence.js +7 -2
- package/backend/src/real-time/socketHandler.js +395 -4
- package/backend/src/server.js +18 -0
- package/frontend/dist/assets/index-DqzDkFsP.js +11210 -0
- package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package-lock.json +9437 -0
- package/frontend/package.json +8 -0
- package/package.json +2 -2
- package/screen/console.png +0 -0
- package/screen/dashboard.png +0 -0
- package/screen/graph_collabe.png +0 -0
- package/screen/graph_live_debug.png +0 -0
- package/screen/management_command.png +0 -0
- package/screen/node_debug_trace.png +0 -0
- package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
- package/screen/websocket.png +0 -0
- package/screen//320/275/320/260/321/201/321/202/321/200/320/276/320/271/320/272/320/270_/320/276/321/202/320/264/320/265/320/273/321/214/320/275/321/213/321/205_/320/272/320/276/320/274/320/260/320/275/320/264_/320/272/320/260/320/266/320/264/321/203_/320/272/320/276/320/274/320/260/320/275/320/273/320/264/321/203_/320/274/320/276/320/266/320/275/320/276_/320/275/320/260/321/201/321/202/321/200/320/260/320/270/320/262/320/260/321/202/321/214.png +0 -0
- package/screen//320/277/320/273/320/260/320/275/320/270/321/200/320/276/320/262/321/211/320/270/320/272_/320/274/320/276/320/266/320/275/320/276_/320/267/320/260/320/264/320/260/320/262/320/260/321/202/321/214_/320/264/320/265/320/271/321/201/321/202/320/262/320/270/321/217_/320/277/320/276_/320/262/321/200/320/265/320/274/320/265/320/275/320/270.png +0 -0
- package/frontend/dist/assets/index-CfTo92bP.css +0 -1
- package/frontend/dist/assets/index-CiFD5X9Z.js +0 -8344
|
@@ -4,8 +4,18 @@ const config = require('../config');
|
|
|
4
4
|
const { botManager } = require('../core/services');
|
|
5
5
|
const presence = require('./presence');
|
|
6
6
|
const { initializeBotApiNamespace } = require('./botApi');
|
|
7
|
+
const { initializePanelNamespace, broadcastToPanelNamespace } = require('./panelNamespace');
|
|
8
|
+
const { getTraceCollector } = require('../core/services/TraceCollectorService');
|
|
9
|
+
const { initializeDebugManager, getGlobalDebugManager } = require('../core/services/DebugSessionManager');
|
|
10
|
+
const { initializeCollaborationManager, getGlobalCollaborationManager } = require('../core/services/GraphCollaborationManager');
|
|
11
|
+
const MinecraftViewerService = require('../core/services/MinecraftViewerService');
|
|
7
12
|
|
|
8
13
|
let io;
|
|
14
|
+
let minecraftViewerService;
|
|
15
|
+
|
|
16
|
+
// Буфер логов для каждого плагина (последние 100 логов)
|
|
17
|
+
const pluginLogsBuffer = new Map(); // key: 'botId:pluginName', value: array of logs
|
|
18
|
+
const MAX_LOGS_PER_PLUGIN = 100;
|
|
9
19
|
|
|
10
20
|
function initializeSocket(httpServer) {
|
|
11
21
|
const corsOptions = {
|
|
@@ -19,22 +29,376 @@ function initializeSocket(httpServer) {
|
|
|
19
29
|
transports: ['websocket', 'polling']
|
|
20
30
|
});
|
|
21
31
|
|
|
22
|
-
// Инициализируем
|
|
32
|
+
// Инициализируем TraceCollector с Socket.IO
|
|
33
|
+
const traceCollector = getTraceCollector();
|
|
34
|
+
traceCollector.setSocketIO(io);
|
|
35
|
+
|
|
36
|
+
initializeDebugManager(io);
|
|
37
|
+
initializeCollaborationManager(io);
|
|
38
|
+
|
|
39
|
+
// Инициализируем Panel WebSocket namespace
|
|
40
|
+
initializePanelNamespace(io);
|
|
41
|
+
|
|
23
42
|
initializeBotApiNamespace(io);
|
|
24
43
|
|
|
44
|
+
// Инициализируем Minecraft Viewer Service
|
|
45
|
+
const logger = {
|
|
46
|
+
debug: (...args) => console.log('[DEBUG]', ...args),
|
|
47
|
+
info: (...args) => console.log('[INFO]', ...args),
|
|
48
|
+
warn: (...args) => console.warn('[WARN]', ...args),
|
|
49
|
+
error: (...args) => console.error('[ERROR]', ...args),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
minecraftViewerService = new MinecraftViewerService({
|
|
53
|
+
io,
|
|
54
|
+
botProcessManager: botManager.processManager,
|
|
55
|
+
logger
|
|
56
|
+
});
|
|
57
|
+
|
|
25
58
|
io.on('connection', (socket) => {
|
|
59
|
+
// Сохраняем decoded информацию о пользователе из токена
|
|
60
|
+
const token = socket.handshake?.auth?.token;
|
|
61
|
+
if (token) {
|
|
62
|
+
const jwt = require('jsonwebtoken');
|
|
63
|
+
const config = require('../config');
|
|
64
|
+
try {
|
|
65
|
+
socket.decoded = jwt.verify(token, config.security.jwtSecret, { algorithms: ['HS256'] });
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.warn('[Socket] Failed to decode token:', e.message);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
26
71
|
presence.handleConnection(io, socket);
|
|
27
72
|
|
|
28
73
|
socket.on('disconnect', () => {
|
|
29
74
|
botManager.handleSocketDisconnect(socket);
|
|
75
|
+
|
|
76
|
+
// Удаляем пользователя из всех debug комнат
|
|
77
|
+
const debugManager = getGlobalDebugManager();
|
|
78
|
+
for (const [graphId, debugState] of debugManager.graphDebugStates) {
|
|
79
|
+
if (debugState.connectedUsers.has(socket.id)) {
|
|
80
|
+
debugState.removeUser(socket.id);
|
|
81
|
+
const room = debugState.getRoomName();
|
|
82
|
+
io.to(room).emit('debug:user-left', {
|
|
83
|
+
userCount: debugState.connectedUsers.size,
|
|
84
|
+
users: Array.from(debugState.connectedUsers.values())
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
30
88
|
});
|
|
31
89
|
|
|
32
90
|
socket.on('plugin:ui:subscribe', ({ botId, pluginName }) => {
|
|
33
91
|
botManager.subscribeToPluginUi(botId, pluginName, socket);
|
|
34
92
|
});
|
|
35
93
|
|
|
36
|
-
socket.on('
|
|
37
|
-
|
|
94
|
+
socket.on('debug:join', ({ botId, graphId }) => {
|
|
95
|
+
try {
|
|
96
|
+
const debugManager = getGlobalDebugManager();
|
|
97
|
+
const username = socket.decoded?.username || 'Anonymous';
|
|
98
|
+
const userId = socket.decoded?.userId || null;
|
|
99
|
+
|
|
100
|
+
console.log(`[Debug] User ${username} joining debug session for graph ${graphId} (bot ${botId})`);
|
|
101
|
+
|
|
102
|
+
const debugState = debugManager.getOrCreate(botId, graphId);
|
|
103
|
+
|
|
104
|
+
debugState.addUser(socket.id, { userId, username, socketId: socket.id });
|
|
105
|
+
|
|
106
|
+
const room = debugState.getRoomName();
|
|
107
|
+
socket.join(room);
|
|
108
|
+
|
|
109
|
+
socket.emit('debug:state', {
|
|
110
|
+
breakpoints: Array.from(debugState.breakpoints.entries()).map(([nodeId, bp]) => ({
|
|
111
|
+
nodeId,
|
|
112
|
+
enabled: bp.enabled,
|
|
113
|
+
condition: bp.condition
|
|
114
|
+
})),
|
|
115
|
+
connectedUsers: Array.from(debugState.connectedUsers.values())
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
socket.to(room).emit('debug:user-joined', {
|
|
120
|
+
username,
|
|
121
|
+
socketId: socket.id,
|
|
122
|
+
userCount: debugState.connectedUsers.size
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('[Debug] Error joining debug session:', error);
|
|
127
|
+
socket.emit('debug:error', { message: 'Failed to join debug session' });
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
socket.on('debug:leave', ({ botId, graphId }) => {
|
|
132
|
+
const debugManager = getGlobalDebugManager();
|
|
133
|
+
const debugState = debugManager.get(graphId);
|
|
134
|
+
|
|
135
|
+
if (!debugState) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const room = debugState.getRoomName();
|
|
140
|
+
debugState.removeUser(socket.id);
|
|
141
|
+
|
|
142
|
+
// Если это был последний пользователь - очищаем breakpoints
|
|
143
|
+
if (debugState.connectedUsers.size === 0) {
|
|
144
|
+
debugState.clearAllBreakpoints();
|
|
145
|
+
|
|
146
|
+
// Если есть активное выполнение на паузе - останавливаем его
|
|
147
|
+
if (debugState.activeExecution) {
|
|
148
|
+
debugState.stop();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
socket.leave(room);
|
|
153
|
+
|
|
154
|
+
socket.to(room).emit('debug:user-left', {
|
|
155
|
+
userCount: debugState.connectedUsers.size,
|
|
156
|
+
users: Array.from(debugState.connectedUsers.values())
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
socket.on('debug:set-breakpoint', ({ graphId, nodeId, condition }) => {
|
|
161
|
+
const debugManager = getGlobalDebugManager();
|
|
162
|
+
const debugState = debugManager.get(graphId);
|
|
163
|
+
if (!debugState) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
debugState.addBreakpoint(nodeId, condition, socket.id);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
socket.on('debug:remove-breakpoint', ({ graphId, nodeId }) => {
|
|
171
|
+
const debugManager = getGlobalDebugManager();
|
|
172
|
+
const debugState = debugManager.get(graphId);
|
|
173
|
+
if (!debugState) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
debugState.removeBreakpoint(nodeId);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
socket.on('debug:toggle-breakpoint', ({ graphId, nodeId, enabled }) => {
|
|
181
|
+
const debugManager = getGlobalDebugManager();
|
|
182
|
+
const debugState = debugManager.get(graphId);
|
|
183
|
+
if (!debugState) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
debugState.toggleBreakpoint(nodeId, enabled);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
socket.on('debug:continue', ({ sessionId, overrides, stepMode }) => {
|
|
191
|
+
const debugManager = getGlobalDebugManager();
|
|
192
|
+
const debugState = debugManager.getBySessionId(sessionId);
|
|
193
|
+
if (!debugState) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
debugState.resume(overrides, stepMode || false);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
socket.on('debug:stop', ({ sessionId }) => {
|
|
201
|
+
const debugManager = getGlobalDebugManager();
|
|
202
|
+
const debugState = debugManager.getBySessionId(sessionId);
|
|
203
|
+
if (!debugState) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
debugState.stop();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
socket.on('debug:update-value', ({ botId, graphId, key, value }) => {
|
|
211
|
+
const debugManager = getGlobalDebugManager();
|
|
212
|
+
const debugState = debugManager.get(graphId);
|
|
213
|
+
if (!debugState) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
console.log(`[Debug] Value updated by ${socket.decoded?.username || 'Unknown'}: ${key} =`, value);
|
|
218
|
+
|
|
219
|
+
// Сохраняем изменение в pendingOverrides
|
|
220
|
+
debugState.setValue(key, value);
|
|
221
|
+
|
|
222
|
+
// Транслируем изменение всем подключенным пользователям
|
|
223
|
+
debugState.broadcast('debug:value-updated', {
|
|
224
|
+
key,
|
|
225
|
+
value,
|
|
226
|
+
updatedBy: socket.decoded?.username || 'Unknown'
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Hot reload графов при сохранении
|
|
231
|
+
socket.on('graph:updated', async ({ botId, graphId }) => {
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
const eventGraphManager = botManager.eventGraphManager;
|
|
235
|
+
|
|
236
|
+
if (eventGraphManager) {
|
|
237
|
+
// Перезагружаем графы для бота
|
|
238
|
+
await eventGraphManager.loadGraphsForBot(botId);
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
// Уведомляем всех пользователей о перезагрузке через collaboration manager
|
|
242
|
+
const collabManager = getGlobalCollaborationManager();
|
|
243
|
+
collabManager.broadcastGraphReloaded(botId, graphId);
|
|
244
|
+
} else {
|
|
245
|
+
console.warn(`[Graph Hot Reload] EventGraphManager not found!`);
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error(`[Graph Hot Reload] Error reloading graphs for bot ${botId}:`, error);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// ========== COLLABORATIVE EDITING EVENTS ==========
|
|
253
|
+
|
|
254
|
+
// Присоединение к графу для совместного редактирования
|
|
255
|
+
socket.on('collab:join', ({ botId, graphId, debugMode }) => {
|
|
256
|
+
try {
|
|
257
|
+
const collabManager = getGlobalCollaborationManager();
|
|
258
|
+
const username = socket.decoded?.username || 'Anonymous';
|
|
259
|
+
const userId = socket.decoded?.userId || null;
|
|
260
|
+
|
|
261
|
+
collabManager.joinGraph(socket, { botId, graphId, username, userId, debugMode });
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error('[Collab] Error joining graph:', error);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Покидание графа
|
|
268
|
+
socket.on('collab:leave', ({ botId, graphId }) => {
|
|
269
|
+
try {
|
|
270
|
+
const collabManager = getGlobalCollaborationManager();
|
|
271
|
+
collabManager.leaveGraph(socket, { botId, graphId });
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error('[Collab] Error leaving graph:', error);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Обновление позиции курсора
|
|
278
|
+
socket.on('collab:cursor', ({ botId, graphId, x, y }) => {
|
|
279
|
+
try {
|
|
280
|
+
const collabManager = getGlobalCollaborationManager();
|
|
281
|
+
collabManager.updateCursor(socket, { botId, graphId, x, y });
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error('[Collab] Error updating cursor:', error);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Обновление выбранных нод
|
|
288
|
+
socket.on('collab:selection', ({ botId, graphId, nodeIds }) => {
|
|
289
|
+
try {
|
|
290
|
+
const collabManager = getGlobalCollaborationManager();
|
|
291
|
+
collabManager.updateSelectedNodes(socket, { botId, graphId, nodeIds });
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error('[Collab] Error updating selection:', error);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// Изменение режима отладки
|
|
298
|
+
socket.on('collab:mode-change', ({ botId, graphId, debugMode }) => {
|
|
299
|
+
try {
|
|
300
|
+
const collabManager = getGlobalCollaborationManager();
|
|
301
|
+
collabManager.updateDebugMode(socket, { botId, graphId, debugMode });
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error('[Collab] Error updating debug mode:', error);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Инициализация состояния графа (вызывается первым пользователем после загрузки)
|
|
308
|
+
socket.on('collab:init-graph-state', ({ botId, graphId, nodes, edges }) => {
|
|
309
|
+
try {
|
|
310
|
+
const collabManager = getGlobalCollaborationManager();
|
|
311
|
+
collabManager.initializeGraphState(socket, { botId, graphId, nodes, edges });
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.error('[Collab] Error initializing graph state:', error);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Изменение нод (движение, создание, удаление, обновление)
|
|
318
|
+
socket.on('collab:nodes', ({ botId, graphId, type, data }) => {
|
|
319
|
+
try {
|
|
320
|
+
const collabManager = getGlobalCollaborationManager();
|
|
321
|
+
collabManager.broadcastNodeChange(socket, { botId, graphId, type, data });
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.error('[Collab] Error broadcasting node change:', error);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Изменение связей (создание, удаление)
|
|
328
|
+
socket.on('collab:edges', ({ botId, graphId, type, data }) => {
|
|
329
|
+
try {
|
|
330
|
+
const collabManager = getGlobalCollaborationManager();
|
|
331
|
+
collabManager.broadcastEdgeChange(socket, { botId, graphId, type, data });
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error('[Collab] Error broadcasting edge change:', error);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Начало создания соединения (пользователь начал тянуть линию)
|
|
338
|
+
socket.on('collab:connection-start', ({ botId, graphId, fromX, fromY, fromNodeId, fromHandleId }) => {
|
|
339
|
+
try {
|
|
340
|
+
const collabManager = getGlobalCollaborationManager();
|
|
341
|
+
collabManager.startConnection(socket, { botId, graphId, fromX, fromY, fromNodeId, fromHandleId });
|
|
342
|
+
} catch (error) {
|
|
343
|
+
console.error('[Collab] Error starting connection:', error);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Обновление позиции соединения (пользователь двигает мышью с зажатой линией)
|
|
348
|
+
socket.on('collab:connection-update', ({ botId, graphId, toX, toY }) => {
|
|
349
|
+
try {
|
|
350
|
+
const collabManager = getGlobalCollaborationManager();
|
|
351
|
+
collabManager.updateConnection(socket, { botId, graphId, toX, toY });
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error('[Collab] Error updating connection:', error);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Завершение создания соединения (пользователь отпустил линию)
|
|
358
|
+
socket.on('collab:connection-end', ({ botId, graphId }) => {
|
|
359
|
+
try {
|
|
360
|
+
const collabManager = getGlobalCollaborationManager();
|
|
361
|
+
collabManager.endConnection(socket, { botId, graphId });
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error('[Collab] Error ending connection:', error);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// Plugin Logs - подписка на логи плагина
|
|
368
|
+
socket.on('subscribe-plugin-logs', ({ botId, pluginName }) => {
|
|
369
|
+
const room = `plugin-logs:${botId}:${pluginName}`;
|
|
370
|
+
socket.join(room);
|
|
371
|
+
|
|
372
|
+
// Отправляем буфер логов при подключении (одним массивом)
|
|
373
|
+
const bufferKey = `${botId}:${pluginName}`;
|
|
374
|
+
const bufferedLogs = pluginLogsBuffer.get(bufferKey) || [];
|
|
375
|
+
|
|
376
|
+
// Отправляем буфер отдельным событием, чтобы фронтенд мог сбросить state
|
|
377
|
+
socket.emit('plugin-logs-buffer', bufferedLogs);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// Plugin Logs - отписка от логов плагина
|
|
381
|
+
socket.on('unsubscribe-plugin-logs', ({ botId, pluginName }) => {
|
|
382
|
+
const room = `plugin-logs:${botId}:${pluginName}`;
|
|
383
|
+
socket.leave(room);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Plugin Logs - очистка буфера логов плагина
|
|
387
|
+
socket.on('clear-plugin-logs', ({ botId, pluginName }) => {
|
|
388
|
+
const bufferKey = `${botId}:${pluginName}`;
|
|
389
|
+
pluginLogsBuffer.delete(bufferKey);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// При отключении удаляем пользователя из всех комнат
|
|
393
|
+
socket.on('disconnect', () => {
|
|
394
|
+
try {
|
|
395
|
+
const collabManager = getGlobalCollaborationManager();
|
|
396
|
+
collabManager.removeUserFromAllRooms(socket);
|
|
397
|
+
} catch (error) {
|
|
398
|
+
if (error.message !== 'GraphCollaborationManager not initialized! Call initializeCollaborationManager(io) first.') {
|
|
399
|
+
console.error('[Collab] Error on disconnect:', error);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
38
402
|
});
|
|
39
403
|
});
|
|
40
404
|
|
|
@@ -48,4 +412,31 @@ function getIO() {
|
|
|
48
412
|
return io;
|
|
49
413
|
}
|
|
50
414
|
|
|
51
|
-
|
|
415
|
+
function getIOSafe() {
|
|
416
|
+
if (!io) {
|
|
417
|
+
return {
|
|
418
|
+
emit: () => {},
|
|
419
|
+
to: () => ({ emit: () => {} }),
|
|
420
|
+
on: () => {},
|
|
421
|
+
off: () => {},
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
return io;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function addPluginLogToBuffer(botId, pluginName, logEntry) {
|
|
428
|
+
const bufferKey = `${botId}:${pluginName}`;
|
|
429
|
+
|
|
430
|
+
if (!pluginLogsBuffer.has(bufferKey)) {
|
|
431
|
+
pluginLogsBuffer.set(bufferKey, []);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const buffer = pluginLogsBuffer.get(bufferKey);
|
|
435
|
+
buffer.push(logEntry);
|
|
436
|
+
|
|
437
|
+
if (buffer.length > MAX_LOGS_PER_PLUGIN) {
|
|
438
|
+
buffer.shift();
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
module.exports = { initializeSocket, getIO, getIOSafe, addPluginLogToBuffer, broadcastToPanelNamespace };
|
package/backend/src/server.js
CHANGED
|
@@ -12,9 +12,11 @@ const { botManager, pluginManager } = require('./core/services');
|
|
|
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
|
+
const proxiesRoutes = require('./api/routes/proxies');
|
|
15
16
|
const permissionsRoutes = require('./api/routes/permissions');
|
|
16
17
|
const taskRoutes = require('./api/routes/tasks');
|
|
17
18
|
const { router: authRoutes, ALL_PERMISSIONS, VIEWER_PERMISSIONS } = require('./api/routes/auth');
|
|
19
|
+
const panelApiKeysRoutes = require('./api/routes/panelApiKeys');
|
|
18
20
|
const searchRoutes = require('./api/routes/search');
|
|
19
21
|
const eventGraphsRouter = require('./api/routes/eventGraphs');
|
|
20
22
|
const TaskScheduler = require('./core/TaskScheduler');
|
|
@@ -22,6 +24,13 @@ const panelRoutes = require('./api/routes/panel');
|
|
|
22
24
|
const changelogRoutes = require('./api/routes/changelog');
|
|
23
25
|
const logsRoutes = require('./api/routes/logs');
|
|
24
26
|
const systemRoutes = require('./api/routes/system');
|
|
27
|
+
const tracesRoutes = require('./api/routes/traces');
|
|
28
|
+
const botHistoryRoutes = require('./api/routes/botHistory');
|
|
29
|
+
const botUsersRoutes = require('./api/routes/botUsers');
|
|
30
|
+
const botCommandsRoutes = require('./api/routes/botCommands');
|
|
31
|
+
const botGroupsRoutes = require('./api/routes/botGroups');
|
|
32
|
+
const botPermissionsRoutes = require('./api/routes/botPermissions');
|
|
33
|
+
const botStatusRoutes = require('./api/routes/botStatus');
|
|
25
34
|
|
|
26
35
|
const app = express();
|
|
27
36
|
const server = http.createServer(app);
|
|
@@ -41,6 +50,7 @@ const frontendPath = path.resolve(__dirname, '..', '..', 'frontend', 'dist');
|
|
|
41
50
|
const rootPath = path.resolve(__dirname, '..', '..');
|
|
42
51
|
|
|
43
52
|
app.use('/api/auth', authRoutes);
|
|
53
|
+
app.use('/api/panel/api-keys', panelApiKeysRoutes);
|
|
44
54
|
|
|
45
55
|
app.use('/api/version', (req, res, next) => {
|
|
46
56
|
async function getVersion() {
|
|
@@ -57,15 +67,23 @@ app.use('/api/version', (req, res, next) => {
|
|
|
57
67
|
getVersion();
|
|
58
68
|
});
|
|
59
69
|
app.use('/api/tasks', taskRoutes);
|
|
70
|
+
app.use('/api/bots', botUsersRoutes);
|
|
71
|
+
app.use('/api/bots', botCommandsRoutes);
|
|
72
|
+
app.use('/api/bots', botGroupsRoutes);
|
|
73
|
+
app.use('/api/bots', botPermissionsRoutes);
|
|
74
|
+
app.use('/api/bots', botStatusRoutes);
|
|
60
75
|
app.use('/api/bots', botRoutes);
|
|
76
|
+
app.use('/api/bot-history', botHistoryRoutes);
|
|
61
77
|
app.use('/api/plugins', pluginRoutes);
|
|
62
78
|
app.use('/api/servers', serverRoutes);
|
|
79
|
+
app.use('/api/proxies', proxiesRoutes);
|
|
63
80
|
app.use('/api/permissions', permissionsRoutes);
|
|
64
81
|
app.use('/api/search', searchRoutes);
|
|
65
82
|
app.use('/api/panel', panelRoutes);
|
|
66
83
|
app.use('/api/changelog', changelogRoutes);
|
|
67
84
|
app.use('/api/logs', logsRoutes);
|
|
68
85
|
app.use('/api/system', systemRoutes);
|
|
86
|
+
app.use('/api/traces', tracesRoutes);
|
|
69
87
|
|
|
70
88
|
app.use(express.static(frontendPath));
|
|
71
89
|
|