blockmine 1.25.0 → 1.27.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 +46 -1
- package/backend/cli.js +1 -1
- package/backend/package.json +2 -2
- package/backend/prisma/migrations/20260328173000_add_plugin_source_ref/migration.sql +2 -0
- package/backend/prisma/migrations/migration_lock.toml +2 -2
- package/backend/prisma/schema.prisma +2 -0
- package/backend/src/api/routes/apiKeys.js +8 -0
- package/backend/src/api/routes/bots.js +258 -9
- package/backend/src/api/routes/eventGraphs.js +151 -1
- package/backend/src/api/routes/health.js +38 -0
- package/backend/src/api/routes/nodeRegistry.js +63 -0
- package/backend/src/api/routes/plugins.js +254 -29
- package/backend/src/container.js +11 -8
- package/backend/src/core/BotCommandLoader.js +161 -0
- package/backend/src/core/BotConnection.js +125 -0
- package/backend/src/core/BotEventHandlers.js +234 -0
- package/backend/src/core/BotIPCHandler.js +445 -0
- package/backend/src/core/BotManager.js +15 -7
- package/backend/src/core/BotProcess.js +75 -142
- package/backend/src/core/EventGraphManager.js +7 -3
- package/backend/src/core/GraphDebugHandler.js +229 -0
- package/backend/src/core/GraphDebugIPC.js +117 -0
- package/backend/src/core/GraphExecutionEngine.js +545 -978
- package/backend/src/core/GraphTraversal.js +80 -0
- package/backend/src/core/GraphValidation.js +73 -0
- package/backend/src/core/NodeDefinition.js +138 -0
- package/backend/src/core/NodeRegistry.js +153 -141
- package/backend/src/core/PluginManager.js +272 -31
- package/backend/src/core/RewindSignal.js +9 -0
- package/backend/src/core/config/ConfigValidator.js +72 -0
- package/backend/src/core/config/FeatureFlags.js +52 -0
- package/backend/src/core/config/__tests__/ConfigValidator.test.js +232 -0
- package/backend/src/core/domain/entities/Bot.js +39 -0
- package/backend/src/core/domain/entities/Command.js +41 -0
- package/backend/src/core/domain/entities/EventGraph.js +39 -0
- package/backend/src/core/domain/entities/Plugin.js +45 -0
- package/backend/src/core/domain/entities/User.js +40 -0
- package/backend/src/core/domain/services/DependencyResolver.js +168 -0
- package/backend/src/core/domain/services/GraphValidator.js +117 -0
- package/backend/src/core/domain/services/PermissionChecker.js +34 -0
- package/backend/src/core/domain/services/__tests__/DependencyResolver.test.js +126 -0
- package/backend/src/core/domain/valueObjects/BotConfig.js +27 -0
- package/backend/src/core/domain/valueObjects/DependencyGraph.js +86 -0
- package/backend/src/core/domain/valueObjects/PluginManifest.js +36 -0
- package/backend/src/core/errors/BaseError.js +29 -0
- package/backend/src/core/errors/ErrorHandler.js +81 -0
- package/backend/src/core/errors/__tests__/ErrorHandler.test.js +188 -0
- package/backend/src/core/errors/index.js +68 -0
- package/backend/src/core/infrastructure/BatchingUtility.js +66 -0
- package/backend/src/core/infrastructure/CircuitBreaker.js +103 -0
- package/backend/src/core/infrastructure/ConnectionPool.js +81 -0
- package/backend/src/core/infrastructure/RateLimiter.js +64 -0
- package/backend/src/core/infrastructure/__tests__/BatchingUtility.test.js +86 -0
- package/backend/src/core/infrastructure/__tests__/CircuitBreaker.test.js +156 -0
- package/backend/src/core/infrastructure/__tests__/ConnectionPool.test.js +146 -0
- package/backend/src/core/infrastructure/__tests__/RateLimiter.test.js +171 -0
- package/backend/src/core/ipc/botApiFactory.js +72 -0
- package/backend/src/core/ipc/ipcMessageTypes.js +115 -0
- package/backend/src/core/logging/AuditLogger.js +61 -0
- package/backend/src/core/logging/StructuredLogger.js +80 -0
- package/backend/src/core/logging/__tests__/StructuredLogger.test.js +213 -0
- package/backend/src/core/logging/index.js +7 -0
- package/backend/src/core/metrics/MetricsCollector.js +104 -0
- package/backend/src/core/metrics/__tests__/MetricsCollector.test.js +131 -0
- package/backend/src/core/node-registries/actionsNodes.js +191 -0
- package/backend/src/core/node-registries/arraysNodes.js +152 -0
- package/backend/src/core/node-registries/botNodes.js +48 -0
- package/backend/src/core/node-registries/containerNodes.js +141 -0
- package/backend/src/core/node-registries/dataNodes.js +284 -0
- package/backend/src/core/node-registries/debugNodes.js +23 -0
- package/backend/src/core/node-registries/eventsNodes.js +223 -0
- package/backend/src/core/node-registries/flowNodes.js +151 -0
- package/backend/src/core/node-registries/furnaceNodes.js +123 -0
- package/backend/src/core/node-registries/index.js +108 -0
- package/backend/src/core/node-registries/inventory.js +102 -106
- package/backend/src/core/node-registries/logicNodes.js +54 -0
- package/backend/src/core/node-registries/mathNodes.js +38 -0
- package/backend/src/core/node-registries/navigationNodes.js +109 -0
- package/backend/src/core/node-registries/objectsNodes.js +90 -0
- package/backend/src/core/node-registries/stringsNodes.js +165 -0
- package/backend/src/core/node-registries/timeNodes.js +105 -0
- package/backend/src/core/node-registries/typeNodes.js +22 -0
- package/backend/src/core/node-registries/usersNodes.js +126 -0
- package/backend/src/core/nodes/arrays/shuffle.js +14 -0
- package/backend/src/core/nodes/bot/get_name.js +8 -0
- package/backend/src/core/nodes/bot/stop_bot.js +5 -0
- package/backend/src/core/nodes/container/open.js +101 -111
- package/backend/src/core/nodes/data/store_read.js +26 -0
- package/backend/src/core/nodes/data/store_write.js +23 -0
- package/backend/src/core/nodes/event/call_event.js +31 -0
- package/backend/src/core/nodes/event/custom_event.js +8 -0
- package/backend/src/core/nodes/flow/timer.js +35 -0
- package/backend/src/core/nodes/inventory/drop.js +73 -65
- package/backend/src/core/nodes/inventory/equip.js +54 -45
- package/backend/src/core/nodes/inventory/select_slot.js +48 -46
- package/backend/src/core/nodes/navigation/follow.js +54 -51
- package/backend/src/core/nodes/navigation/go_to.js +41 -53
- package/backend/src/core/nodes/navigation/go_to_entity.js +65 -69
- package/backend/src/core/nodes/navigation/go_to_player.js +65 -70
- package/backend/src/core/nodes/navigation/stop.js +17 -26
- package/backend/src/core/nodes/users/add_to_group.js +24 -0
- package/backend/src/core/nodes/users/check_permission.js +26 -0
- package/backend/src/core/nodes/users/remove_from_group.js +24 -0
- package/backend/src/core/services/BotIPCMessageRouter.js +337 -0
- package/backend/src/core/services/BotLifecycleService.js +41 -632
- package/backend/src/core/services/CacheManager.js +83 -23
- package/backend/src/core/services/CrashRestartManager.js +42 -0
- package/backend/src/core/services/DebugSessionManager.js +114 -12
- package/backend/src/core/services/EventGraphService.js +69 -0
- package/backend/src/core/services/MinecraftBotManager.js +9 -1
- package/backend/src/core/services/PluginManagementService.js +84 -0
- package/backend/src/core/services/TestModeContext.js +65 -0
- package/backend/src/core/services/__tests__/CacheManager.test.js +168 -0
- package/backend/src/core/services.js +1 -11
- package/backend/src/core/validation/InputValidator.js +167 -0
- package/backend/src/core/validation/__tests__/InputValidator.test.js +296 -0
- package/backend/src/real-time/botApi/index.js +1 -1
- package/backend/src/real-time/socketHandler.js +26 -0
- package/backend/src/server.js +10 -5
- package/frontend/dist/assets/{browser-ponyfill-DN7pwmHT.js → browser-ponyfill-D8y0Ty7C.js} +1 -1
- package/frontend/dist/assets/index-CFJLS0dk.css +32 -0
- package/frontend/dist/assets/{index-LSy71uwm.js → index-D91UGNMG.js} +1880 -1881
- package/frontend/dist/index.html +2 -2
- package/frontend/dist/locales/en/bots.json +4 -1
- package/frontend/dist/locales/en/common.json +7 -1
- package/frontend/dist/locales/en/login.json +2 -0
- package/frontend/dist/locales/en/management.json +79 -1
- package/frontend/dist/locales/en/nodes.json +59 -4
- package/frontend/dist/locales/en/plugin-detail.json +24 -4
- package/frontend/dist/locales/en/plugins.json +226 -7
- package/frontend/dist/locales/en/setup.json +2 -0
- package/frontend/dist/locales/en/sidebar.json +171 -3
- package/frontend/dist/locales/en/visual-editor.json +230 -31
- package/frontend/dist/locales/ru/bots.json +4 -1
- package/frontend/dist/locales/ru/login.json +2 -0
- package/frontend/dist/locales/ru/management.json +79 -1
- package/frontend/dist/locales/ru/minecraft-viewer.json +3 -0
- package/frontend/dist/locales/ru/nodes.json +105 -51
- package/frontend/dist/locales/ru/plugins.json +103 -4
- package/frontend/dist/locales/ru/setup.json +2 -0
- package/frontend/dist/locales/ru/sidebar.json +171 -3
- package/frontend/dist/locales/ru/visual-editor.json +232 -33
- package/frontend/package.json +2 -0
- package/nul +12 -0
- package/package.json +3 -3
- package/scripts/postinstall.js +38 -0
- package/backend/package-lock.json +0 -6801
- package/backend/src/core/node-registries/actions.js +0 -202
- package/backend/src/core/node-registries/arrays.js +0 -155
- package/backend/src/core/node-registries/bot.js +0 -23
- package/backend/src/core/node-registries/container.js +0 -162
- package/backend/src/core/node-registries/data.js +0 -290
- package/backend/src/core/node-registries/debug.js +0 -26
- package/backend/src/core/node-registries/events.js +0 -201
- package/backend/src/core/node-registries/flow.js +0 -139
- package/backend/src/core/node-registries/furnace.js +0 -143
- package/backend/src/core/node-registries/logic.js +0 -62
- package/backend/src/core/node-registries/math.js +0 -42
- package/backend/src/core/node-registries/navigation.js +0 -111
- package/backend/src/core/node-registries/objects.js +0 -98
- package/backend/src/core/node-registries/strings.js +0 -187
- package/backend/src/core/node-registries/time.js +0 -113
- package/backend/src/core/node-registries/type.js +0 -25
- package/backend/src/core/node-registries/users.js +0 -79
- package/frontend/dist/assets/index-SfhKxI4-.css +0 -32
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
const
|
|
1
|
+
const DependencyResolver = require('../domain/services/DependencyResolver');
|
|
2
2
|
const { decrypt } = require('../utils/crypto');
|
|
3
3
|
const UserService = require('../UserService');
|
|
4
4
|
const PermissionManager = require('../PermissionManager');
|
|
5
|
+
const CrashRestartManager = require('./CrashRestartManager');
|
|
6
|
+
const BotIPCMessageRouter = require('./BotIPCMessageRouter');
|
|
7
|
+
const ErrorHandler = require('../errors/ErrorHandler');
|
|
8
|
+
|
|
9
|
+
const dependencyResolver = new DependencyResolver();
|
|
10
|
+
const errorHandler = new ErrorHandler({ logger: console });
|
|
5
11
|
|
|
6
12
|
class BotLifecycleService {
|
|
7
13
|
constructor({
|
|
@@ -30,7 +36,20 @@ class BotLifecycleService {
|
|
|
30
36
|
this.logger = logger;
|
|
31
37
|
|
|
32
38
|
this.logCache = new Map();
|
|
33
|
-
this.
|
|
39
|
+
this.crashRestartManager = new CrashRestartManager(5, 60000);
|
|
40
|
+
|
|
41
|
+
this.ipcRouter = new BotIPCMessageRouter({
|
|
42
|
+
eventGraphManager: this.eventGraphManager,
|
|
43
|
+
commandExecutionService: this.commandExecutionService,
|
|
44
|
+
processManager: this.processManager,
|
|
45
|
+
logger: this.logger,
|
|
46
|
+
crashRestartManager: this.crashRestartManager,
|
|
47
|
+
appendLog: this.appendLog.bind(this),
|
|
48
|
+
emitStatusUpdate: this.emitStatusUpdate.bind(this),
|
|
49
|
+
restartBot: this.restartBot.bind(this),
|
|
50
|
+
stopBot: this.stopBot.bind(this),
|
|
51
|
+
getBotConfig: (botId) => this.processManager.getProcess(botId)?.botConfig,
|
|
52
|
+
});
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
async startBot(botConfig) {
|
|
@@ -47,7 +66,7 @@ class BotLifecycleService {
|
|
|
47
66
|
this.emitStatusUpdate(botId, 'starting', '');
|
|
48
67
|
|
|
49
68
|
const allPluginsForBot = await this.pluginRepository.findEnabledByBotId(botId);
|
|
50
|
-
const { sortedPlugins, hasCriticalIssues, pluginInfo } =
|
|
69
|
+
const { sortedPlugins, hasCriticalIssues, pluginInfo } = dependencyResolver.resolve(allPluginsForBot, allPluginsForBot);
|
|
51
70
|
|
|
52
71
|
if (hasCriticalIssues) {
|
|
53
72
|
this.appendLog(botId, '[DependencyManager] Обнаружены критические проблемы с зависимостями, запуск отменен.');
|
|
@@ -63,7 +82,8 @@ class BotLifecycleService {
|
|
|
63
82
|
if (criticalIssues.length > 0) {
|
|
64
83
|
this.appendLog(botId, `* Плагин "${info.name}":`);
|
|
65
84
|
for (const issue of criticalIssues) {
|
|
66
|
-
|
|
85
|
+
const msg = issue.message || `${issue.messageKey} ${JSON.stringify(issue.context || {})}`;
|
|
86
|
+
this.appendLog(botId, ` - ${msg}`);
|
|
67
87
|
}
|
|
68
88
|
}
|
|
69
89
|
}
|
|
@@ -100,8 +120,7 @@ class BotLifecycleService {
|
|
|
100
120
|
}
|
|
101
121
|
};
|
|
102
122
|
|
|
103
|
-
|
|
104
|
-
this._setupChildProcessHandlers(child, botConfig);
|
|
123
|
+
this.ipcRouter.attachToChild(child, botConfig);
|
|
105
124
|
|
|
106
125
|
child.send({ type: 'start', config: fullBotConfig });
|
|
107
126
|
|
|
@@ -118,14 +137,12 @@ class BotLifecycleService {
|
|
|
118
137
|
if (child) {
|
|
119
138
|
this.eventGraphManager.unloadGraphsForBot(botId);
|
|
120
139
|
|
|
121
|
-
// Очищаем traces для этого бота
|
|
122
140
|
const { getTraceCollector } = require('./TraceCollectorService');
|
|
123
141
|
const traceCollector = getTraceCollector();
|
|
124
142
|
traceCollector.clearForBot(botId);
|
|
125
143
|
|
|
126
144
|
child.send({ type: 'stop' });
|
|
127
145
|
|
|
128
|
-
// Принудительное завершение через 5 секунд
|
|
129
146
|
setTimeout(() => {
|
|
130
147
|
if (!child.killed) {
|
|
131
148
|
this.logger.warn({ botId }, 'Принудительное завершение процесса');
|
|
@@ -154,309 +171,11 @@ class BotLifecycleService {
|
|
|
154
171
|
}
|
|
155
172
|
|
|
156
173
|
await this.stopBot(botId);
|
|
157
|
-
|
|
158
|
-
// Ждём завершения процесса
|
|
159
174
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
160
175
|
|
|
161
176
|
return this.startBot(botConfig);
|
|
162
177
|
}
|
|
163
178
|
|
|
164
|
-
_setupChildProcessHandlers(child, botConfig) {
|
|
165
|
-
const botId = botConfig.id;
|
|
166
|
-
|
|
167
|
-
child.on('message', async (message) => {
|
|
168
|
-
try {
|
|
169
|
-
switch (message.type) {
|
|
170
|
-
case 'event':
|
|
171
|
-
await this._handleEventMessage(botId, message);
|
|
172
|
-
break;
|
|
173
|
-
case 'plugin:data':
|
|
174
|
-
this._handlePluginDataMessage(botId, message);
|
|
175
|
-
break;
|
|
176
|
-
case 'send_websocket_message':
|
|
177
|
-
this._handleWebSocketMessage(message);
|
|
178
|
-
break;
|
|
179
|
-
case 'log':
|
|
180
|
-
this.appendLog(botId, message.content);
|
|
181
|
-
break;
|
|
182
|
-
case 'plugin-log':
|
|
183
|
-
this._handlePluginLog(message.log);
|
|
184
|
-
break;
|
|
185
|
-
case 'status':
|
|
186
|
-
this.emitStatusUpdate(botId, message.status);
|
|
187
|
-
break;
|
|
188
|
-
case 'bot_ready':
|
|
189
|
-
this._handleBotReady(botId);
|
|
190
|
-
break;
|
|
191
|
-
case 'validate_and_run_command':
|
|
192
|
-
if (this.commandExecutionService) {
|
|
193
|
-
const botConfig = child.botConfig;
|
|
194
|
-
if (botConfig) {
|
|
195
|
-
await this.commandExecutionService.handleCommandValidation(botConfig, message);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
break;
|
|
199
|
-
case 'request_user_action':
|
|
200
|
-
await this._handleUserAction(botId, child, message);
|
|
201
|
-
break;
|
|
202
|
-
case 'get_player_list_response':
|
|
203
|
-
this.processManager.resolvePlayerListRequest(message.requestId, message.payload.players);
|
|
204
|
-
break;
|
|
205
|
-
case 'get_nearby_entities_response':
|
|
206
|
-
this.processManager.resolveNearbyEntitiesRequest(message.requestId, message.payload.entities);
|
|
207
|
-
break;
|
|
208
|
-
case 'execute_command_response':
|
|
209
|
-
this.processManager.resolveCommandRequest(message.requestId, message.result, message.error);
|
|
210
|
-
break;
|
|
211
|
-
case 'register_command':
|
|
212
|
-
await this._handleCommandRegistration(botId, message.commandConfig);
|
|
213
|
-
break;
|
|
214
|
-
case 'register_permissions':
|
|
215
|
-
await this._handlePermissionsRegistration(botId, message);
|
|
216
|
-
break;
|
|
217
|
-
case 'register_group':
|
|
218
|
-
await this._handleGroupRegistration(botId, message);
|
|
219
|
-
break;
|
|
220
|
-
case 'add_permissions_to_group':
|
|
221
|
-
await this._handleAddPermissionsToGroup(botId, message);
|
|
222
|
-
break;
|
|
223
|
-
case 'trace:completed':
|
|
224
|
-
await this._handleTraceCompleted(botId, message.trace);
|
|
225
|
-
break;
|
|
226
|
-
case 'debug:check_breakpoint':
|
|
227
|
-
await this._handleDebugBreakpointCheck(botId, child, message);
|
|
228
|
-
break;
|
|
229
|
-
case 'debug:check_step_mode':
|
|
230
|
-
await this._handleDebugStepModeCheck(botId, child, message);
|
|
231
|
-
break;
|
|
232
|
-
case 'update_credentials':
|
|
233
|
-
await this._handleUpdateCredentials(botId, child, message);
|
|
234
|
-
break;
|
|
235
|
-
case 'restart_bot':
|
|
236
|
-
await this._handleRestartBot(botId, child, message);
|
|
237
|
-
break;
|
|
238
|
-
case 'change_credentials':
|
|
239
|
-
await this._handleChangeCredentials(botId, child, message);
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
} catch (error) {
|
|
243
|
-
this.appendLog(botId, `[SYSTEM-ERROR] Критическая ошибка в обработчике: ${error.stack}`);
|
|
244
|
-
this.logger.error({ botId, error }, 'Критическая ошибка в обработчике сообщений');
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
child.on('error', (err) => this.appendLog(botId, `[PROCESS FATAL] ${err.stack}`));
|
|
249
|
-
child.stdout.on('data', (data) => console.log(data.toString()));
|
|
250
|
-
child.stderr.on('data', (data) => this.appendLog(botId, `[STDERR] ${data.toString()}`));
|
|
251
|
-
|
|
252
|
-
child.on('exit', (code, signal) => {
|
|
253
|
-
this._handleProcessExit(botId, botConfig, code, signal);
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async _handleEventMessage(botId, message) {
|
|
258
|
-
if (message.eventType === 'raw_message') {
|
|
259
|
-
try {
|
|
260
|
-
const { getIOSafe } = require('../../real-time/socketHandler');
|
|
261
|
-
const { broadcastToApiClients } = require('../../real-time/botApi');
|
|
262
|
-
broadcastToApiClients(getIOSafe(), botId, 'chat:raw_message', {
|
|
263
|
-
raw_message: message.args.rawText || message.args.raw_message,
|
|
264
|
-
json: message.args.json
|
|
265
|
-
});
|
|
266
|
-
} catch (e) { /* Socket.IO может быть не инициализирован */ }
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
try {
|
|
270
|
-
const { broadcastToPanelNamespace } = require('../../real-time/panelNamespace');
|
|
271
|
-
broadcastToPanelNamespace(botId, 'bot:event', {
|
|
272
|
-
botId,
|
|
273
|
-
eventType: message.eventType,
|
|
274
|
-
data: message.args || {},
|
|
275
|
-
timestamp: new Date().toISOString()
|
|
276
|
-
});
|
|
277
|
-
} catch (e) { /* Socket.IO может быть не инициализирован */ }
|
|
278
|
-
|
|
279
|
-
if (this.eventGraphManager) {
|
|
280
|
-
this.eventGraphManager.handleEvent(botId, message.eventType, message.args);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
_handlePluginDataMessage(botId, message) {
|
|
285
|
-
const { plugin: pluginName, payload } = message;
|
|
286
|
-
const pluginSubscribers = this.processManager.getPluginSubscribers(botId, pluginName);
|
|
287
|
-
|
|
288
|
-
if (pluginSubscribers && pluginSubscribers.size > 0) {
|
|
289
|
-
pluginSubscribers.forEach(socket => {
|
|
290
|
-
socket.emit('plugin:ui:dataUpdate', payload);
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
_handlePluginLog(logData) {
|
|
296
|
-
const { getIOSafe, addPluginLogToBuffer } = require('../../real-time/socketHandler');
|
|
297
|
-
const { botId, pluginName } = logData;
|
|
298
|
-
|
|
299
|
-
// Добавляем лог в буфер
|
|
300
|
-
addPluginLogToBuffer(botId, pluginName, logData);
|
|
301
|
-
|
|
302
|
-
// Отправляем через Socket.IO в комнату плагина
|
|
303
|
-
const io = getIOSafe();
|
|
304
|
-
if (io) {
|
|
305
|
-
const room = `plugin-logs:${botId}:${pluginName}`;
|
|
306
|
-
io.to(room).emit('plugin-log', logData);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
_handleWebSocketMessage(message) {
|
|
311
|
-
const { getIOSafe } = require('../../real-time/socketHandler');
|
|
312
|
-
const { botId, message: msg } = message.payload;
|
|
313
|
-
getIOSafe().to(`bot_${botId}`).emit('bot:message', { message: msg });
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
_handleBotReady(botId) {
|
|
317
|
-
this.emitStatusUpdate(botId, 'running', 'Бот успешно подключился к серверу.');
|
|
318
|
-
this.crashCounters.delete(botId);
|
|
319
|
-
|
|
320
|
-
try {
|
|
321
|
-
const { getIOSafe } = require('../../real-time/socketHandler');
|
|
322
|
-
const { broadcastBotStatus } = require('../../real-time/botApi');
|
|
323
|
-
broadcastBotStatus(getIOSafe(), botId, true);
|
|
324
|
-
} catch (e) { /* Socket.IO может быть не инициализирован */ }
|
|
325
|
-
|
|
326
|
-
// Триггерим событие запуска бота
|
|
327
|
-
if (this.eventGraphManager) {
|
|
328
|
-
this.eventGraphManager.handleEvent(botId, 'botStartup', {});
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async _handleCommandRegistration(botId, commandConfig) {
|
|
333
|
-
if (this.commandExecutionService) {
|
|
334
|
-
await this.commandExecutionService.handleCommandRegistration(botId, commandConfig);
|
|
335
|
-
// this.logger.debug({ botId, commandName: commandConfig.name }, 'Команда зарегистрирована');
|
|
336
|
-
} else {
|
|
337
|
-
this.logger.warn({ botId }, 'CommandExecutionService не доступен для регистрации команды');
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
async _handlePermissionsRegistration(botId, message) {
|
|
342
|
-
try {
|
|
343
|
-
await PermissionManager.registerPermissions(botId, message.permissions);
|
|
344
|
-
this.logger.debug({ botId, count: message.permissions.length }, 'Права зарегистрированы');
|
|
345
|
-
} catch (error) {
|
|
346
|
-
this.logger.error({ botId, error }, 'Ошибка регистрации прав');
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
async _handleGroupRegistration(botId, message) {
|
|
351
|
-
try {
|
|
352
|
-
await PermissionManager.registerGroup(botId, message.groupConfig);
|
|
353
|
-
this.logger.debug({ botId, groupName: message.groupConfig.name }, 'Группа зарегистрирована');
|
|
354
|
-
} catch (error) {
|
|
355
|
-
this.logger.error({ botId, error }, 'Ошибка регистрации группы');
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
async _handleAddPermissionsToGroup(botId, message) {
|
|
360
|
-
try {
|
|
361
|
-
await PermissionManager.addPermissionsToGroup(botId, message.groupName, message.permissionNames);
|
|
362
|
-
this.logger.debug({ botId, groupName: message.groupName, count: message.permissionNames.length }, 'Права добавлены в группу');
|
|
363
|
-
} catch (error) {
|
|
364
|
-
this.logger.error({ botId, error }, 'Ошибка добавления прав в группу');
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
async _handleUserAction(botId, child, message) {
|
|
369
|
-
const { requestId, payload } = message;
|
|
370
|
-
const { targetUsername, action, data } = payload;
|
|
371
|
-
|
|
372
|
-
try {
|
|
373
|
-
const botConfig = child.botConfig;
|
|
374
|
-
const user = await UserService.getUser(targetUsername, botId, botConfig);
|
|
375
|
-
if (!user) throw new Error(`Пользователь ${targetUsername} не найден.`);
|
|
376
|
-
|
|
377
|
-
let result;
|
|
378
|
-
|
|
379
|
-
switch (action) {
|
|
380
|
-
case 'addGroup':
|
|
381
|
-
result = await user.addGroup(data.group);
|
|
382
|
-
break;
|
|
383
|
-
case 'removeGroup':
|
|
384
|
-
result = await user.removeGroup(data.group);
|
|
385
|
-
break;
|
|
386
|
-
case 'getGroups':
|
|
387
|
-
result = user.groups ? user.groups.map(g => g.group.name) : [];
|
|
388
|
-
break;
|
|
389
|
-
case 'getPermissions':
|
|
390
|
-
result = Array.from(user.permissionsSet);
|
|
391
|
-
break;
|
|
392
|
-
case 'isBlacklisted':
|
|
393
|
-
result = user.isBlacklisted;
|
|
394
|
-
break;
|
|
395
|
-
case 'setBlacklisted':
|
|
396
|
-
result = await user.setBlacklist(data.value);
|
|
397
|
-
break;
|
|
398
|
-
default:
|
|
399
|
-
throw new Error(`Неизвестное действие: ${action}`);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
child.send({ type: 'user_action_response', requestId, payload: result });
|
|
403
|
-
} catch (error) {
|
|
404
|
-
this.logger.error({ botId, action, username: targetUsername, error }, 'Ошибка действия пользователя');
|
|
405
|
-
child.send({ type: 'user_action_response', requestId, error: error.message });
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
_handleProcessExit(botId, botConfig, code, signal) {
|
|
410
|
-
this.processManager.remove(botId);
|
|
411
|
-
this.resourceMonitor.clearResourceUsage(botId);
|
|
412
|
-
this.cache.clearBotCache(botId);
|
|
413
|
-
|
|
414
|
-
this.emitStatusUpdate(botId, 'stopped', `Процесс завершился с кодом ${code} (сигнал: ${signal || 'none'}).`);
|
|
415
|
-
|
|
416
|
-
try {
|
|
417
|
-
const { getIOSafe } = require('../../real-time/socketHandler');
|
|
418
|
-
const { broadcastBotStatus } = require('../../real-time/botApi');
|
|
419
|
-
broadcastBotStatus(getIOSafe(), botId, false);
|
|
420
|
-
} catch (e) { /* Socket.IO может быть не инициализирован */ }
|
|
421
|
-
|
|
422
|
-
// Автоперезапуск при критических ошибках
|
|
423
|
-
if (code === 1) {
|
|
424
|
-
this._handleCrashRestart(botId, botConfig);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
_handleCrashRestart(botId, botConfig) {
|
|
429
|
-
const MAX_RESTART_ATTEMPTS = 5;
|
|
430
|
-
const RESTART_COOLDOWN = 60000;
|
|
431
|
-
|
|
432
|
-
const counter = this.crashCounters.get(botId) || { count: 0, firstCrash: Date.now() };
|
|
433
|
-
const timeSinceFirstCrash = Date.now() - counter.firstCrash;
|
|
434
|
-
|
|
435
|
-
if (timeSinceFirstCrash > RESTART_COOLDOWN) {
|
|
436
|
-
counter.count = 0;
|
|
437
|
-
counter.firstCrash = Date.now();
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
counter.count++;
|
|
441
|
-
this.crashCounters.set(botId, counter);
|
|
442
|
-
|
|
443
|
-
if (counter.count >= MAX_RESTART_ATTEMPTS) {
|
|
444
|
-
this.logger.warn({ botId, attempts: counter.count }, 'Автоперезапуск остановлен');
|
|
445
|
-
this.appendLog(botId, `[SYSTEM] Обнаружено ${counter.count} критических ошибок подряд.`);
|
|
446
|
-
this.appendLog(botId, `[SYSTEM] Исправьте проблему и запустите бота вручную.`);
|
|
447
|
-
this.crashCounters.delete(botId);
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
this.logger.info({ botId, attempt: counter.count, max: MAX_RESTART_ATTEMPTS }, 'Перезапуск через 5 секунд');
|
|
452
|
-
this.appendLog(botId, `[SYSTEM] Обнаружена критическая ошибка, перезапуск через 5 секунд... (попытка ${counter.count}/${MAX_RESTART_ATTEMPTS})`);
|
|
453
|
-
|
|
454
|
-
setTimeout(() => {
|
|
455
|
-
this.logger.info({ botId }, 'Выполняется перезапуск');
|
|
456
|
-
this.startBot(botConfig);
|
|
457
|
-
}, 5000);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
179
|
async loadConfigForBot(botId) {
|
|
461
180
|
this.logger.info({ botId }, 'Загрузка конфигурации');
|
|
462
181
|
|
|
@@ -484,6 +203,7 @@ class BotLifecycleService {
|
|
|
484
203
|
return config;
|
|
485
204
|
} catch (error) {
|
|
486
205
|
this.logger.error({ botId, error }, 'Ошибка загрузки конфигурации');
|
|
206
|
+
const handled = errorHandler.handle(error, { botId });
|
|
487
207
|
throw new Error(`Failed to load/cache bot configuration for botId ${botId}: ${error.message}`);
|
|
488
208
|
}
|
|
489
209
|
}
|
|
@@ -520,14 +240,12 @@ class BotLifecycleService {
|
|
|
520
240
|
for (const perm of systemPermissions) {
|
|
521
241
|
const existing = await this.permissionRepository.findByName(botId, perm.name);
|
|
522
242
|
if (existing) {
|
|
523
|
-
// Обновляем описание если изменилось
|
|
524
243
|
if (existing.description !== perm.description) {
|
|
525
244
|
await this.permissionRepository.update(existing.id, {
|
|
526
245
|
description: perm.description
|
|
527
246
|
});
|
|
528
247
|
}
|
|
529
248
|
} else {
|
|
530
|
-
// Создаем новое системное право
|
|
531
249
|
await this.permissionRepository.create({
|
|
532
250
|
botId,
|
|
533
251
|
name: perm.name,
|
|
@@ -553,7 +271,9 @@ class BotLifecycleService {
|
|
|
553
271
|
const newLogs = [...currentLogs.slice(-199), logEntry];
|
|
554
272
|
this.logCache.set(botId, newLogs);
|
|
555
273
|
|
|
556
|
-
|
|
274
|
+
try {
|
|
275
|
+
getIOSafe().emit('bot:log', { botId, log: logEntry });
|
|
276
|
+
} catch (e) {}
|
|
557
277
|
}
|
|
558
278
|
|
|
559
279
|
getBotLogs(botId) {
|
|
@@ -564,14 +284,15 @@ class BotLifecycleService {
|
|
|
564
284
|
const { getIOSafe, broadcastToPanelNamespace } = require('../../real-time/socketHandler');
|
|
565
285
|
if (message) this.appendLog(botId, `[SYSTEM] ${message}`);
|
|
566
286
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
287
|
+
try {
|
|
288
|
+
getIOSafe().emit('bot:status', { botId, status, message });
|
|
289
|
+
broadcastToPanelNamespace(getIOSafe(), 'bots:status', {
|
|
290
|
+
botId,
|
|
291
|
+
status,
|
|
292
|
+
message,
|
|
293
|
+
timestamp: new Date().toISOString()
|
|
294
|
+
});
|
|
295
|
+
} catch (e) {}
|
|
575
296
|
}
|
|
576
297
|
|
|
577
298
|
getFullState() {
|
|
@@ -625,8 +346,6 @@ class BotLifecycleService {
|
|
|
625
346
|
}
|
|
626
347
|
|
|
627
348
|
async getPlayerList(botId) {
|
|
628
|
-
const PLAYER_LIST_CACHE_TTL = 2000;
|
|
629
|
-
|
|
630
349
|
if (!this.processManager.isRunning(botId)) {
|
|
631
350
|
return [];
|
|
632
351
|
}
|
|
@@ -678,8 +397,8 @@ class BotLifecycleService {
|
|
|
678
397
|
timeout
|
|
679
398
|
});
|
|
680
399
|
|
|
681
|
-
this.processManager.sendMessage(botId, {
|
|
682
|
-
type: 'system:get_nearby_entities',
|
|
400
|
+
this.processManager.sendMessage(botId, {
|
|
401
|
+
type: 'system:get_nearby_entities',
|
|
683
402
|
requestId,
|
|
684
403
|
payload: { position, radius }
|
|
685
404
|
});
|
|
@@ -704,316 +423,6 @@ class BotLifecycleService {
|
|
|
704
423
|
|
|
705
424
|
return { success: true };
|
|
706
425
|
}
|
|
707
|
-
|
|
708
|
-
async _handleTraceCompleted(botId, trace) {
|
|
709
|
-
try {
|
|
710
|
-
const { getTraceCollector } = require('../services/TraceCollectorService');
|
|
711
|
-
const traceCollector = getTraceCollector();
|
|
712
|
-
|
|
713
|
-
// Сохраняем трассировку в главном TraceCollectorService
|
|
714
|
-
await traceCollector._storeCompletedTrace(trace);
|
|
715
|
-
} catch (error) {
|
|
716
|
-
this.logger.error({ botId, error }, 'Ошибка обработки завершённой трассировки');
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
async _handleDebugBreakpointCheck(botId, child, message) {
|
|
721
|
-
const { requestId, payload } = message;
|
|
722
|
-
const { graphId, nodeId, nodeType, inputs, executedSteps, context } = payload;
|
|
723
|
-
|
|
724
|
-
try {
|
|
725
|
-
const { getGlobalDebugManager } = require('../services/DebugSessionManager');
|
|
726
|
-
const debugManager = getGlobalDebugManager();
|
|
727
|
-
|
|
728
|
-
const debugState = debugManager.get(graphId);
|
|
729
|
-
if (!debugState) {
|
|
730
|
-
// Нет debug сессии для этого графа - просто продолжаем выполнение
|
|
731
|
-
child.send({
|
|
732
|
-
type: 'debug:breakpoint_response',
|
|
733
|
-
requestId,
|
|
734
|
-
overrides: null
|
|
735
|
-
});
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
const breakpoint = debugState.breakpoints.get(nodeId);
|
|
740
|
-
if (!breakpoint || !breakpoint.enabled) {
|
|
741
|
-
// Нет брейкпоинта для этой ноды или он отключен
|
|
742
|
-
child.send({
|
|
743
|
-
type: 'debug:breakpoint_response',
|
|
744
|
-
requestId,
|
|
745
|
-
overrides: null
|
|
746
|
-
});
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
// Проверяем условие брейкпоинта (пока всегда срабатывает)
|
|
751
|
-
// TODO: добавить evaluateBreakpointCondition
|
|
752
|
-
|
|
753
|
-
breakpoint.hitCount++;
|
|
754
|
-
|
|
755
|
-
// Приостанавливаем выполнение и ждём действий от пользователя
|
|
756
|
-
const overrides = await debugState.pause({
|
|
757
|
-
nodeId,
|
|
758
|
-
nodeType,
|
|
759
|
-
inputs,
|
|
760
|
-
executedSteps,
|
|
761
|
-
context,
|
|
762
|
-
breakpoint: {
|
|
763
|
-
condition: breakpoint.condition,
|
|
764
|
-
hitCount: breakpoint.hitCount
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
|
|
768
|
-
// Отправляем результат обратно в дочерний процесс
|
|
769
|
-
child.send({
|
|
770
|
-
type: 'debug:breakpoint_response',
|
|
771
|
-
requestId,
|
|
772
|
-
overrides: overrides || null
|
|
773
|
-
});
|
|
774
|
-
|
|
775
|
-
} catch (error) {
|
|
776
|
-
this.logger.error({ botId, error }, 'Ошибка обработки debug breakpoint check');
|
|
777
|
-
// В случае ошибки отправляем null чтобы продолжить выполнение
|
|
778
|
-
child.send({
|
|
779
|
-
type: 'debug:breakpoint_response',
|
|
780
|
-
requestId,
|
|
781
|
-
overrides: null
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
async _handleDebugStepModeCheck(botId, child, message) {
|
|
787
|
-
const { requestId, payload } = message;
|
|
788
|
-
const { graphId, nodeId, nodeType, inputs, executedSteps, context } = payload;
|
|
789
|
-
|
|
790
|
-
try {
|
|
791
|
-
const { getGlobalDebugManager } = require('../services/DebugSessionManager');
|
|
792
|
-
const debugManager = getGlobalDebugManager();
|
|
793
|
-
|
|
794
|
-
const debugState = debugManager.get(graphId);
|
|
795
|
-
if (!debugState) {
|
|
796
|
-
// Нет debug сессии - продолжаем выполнение
|
|
797
|
-
child.send({
|
|
798
|
-
type: 'debug:breakpoint_response', // Используем тот же тип ответа
|
|
799
|
-
requestId,
|
|
800
|
-
overrides: null
|
|
801
|
-
});
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
// Проверяем, нужно ли остановиться в step mode
|
|
806
|
-
if (!debugState.shouldStepPause(nodeId)) {
|
|
807
|
-
// Step mode не активен или не нужно останавливаться на этой ноде
|
|
808
|
-
child.send({
|
|
809
|
-
type: 'debug:breakpoint_response',
|
|
810
|
-
requestId,
|
|
811
|
-
overrides: null
|
|
812
|
-
});
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
// Приостанавливаем выполнение и ждём действий от пользователя
|
|
817
|
-
const overrides = await debugState.pause({
|
|
818
|
-
nodeId,
|
|
819
|
-
nodeType,
|
|
820
|
-
inputs,
|
|
821
|
-
executedSteps,
|
|
822
|
-
context
|
|
823
|
-
});
|
|
824
|
-
|
|
825
|
-
// Отправляем результат обратно в дочерний процесс
|
|
826
|
-
child.send({
|
|
827
|
-
type: 'debug:breakpoint_response',
|
|
828
|
-
requestId,
|
|
829
|
-
overrides: overrides || null
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
} catch (error) {
|
|
833
|
-
this.logger.error({ botId, error }, 'Ошибка обработки debug step mode check');
|
|
834
|
-
// В случае ошибки отправляем null чтобы продолжить выполнение
|
|
835
|
-
child.send({
|
|
836
|
-
type: 'debug:breakpoint_response',
|
|
837
|
-
requestId,
|
|
838
|
-
overrides: null
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
/**
|
|
844
|
-
* Обработчик обновления credentials в БД (без рестарта)
|
|
845
|
-
*/
|
|
846
|
-
async _handleUpdateCredentials(botId, child, message) {
|
|
847
|
-
const { requestId, payload } = message;
|
|
848
|
-
const { username, password } = payload;
|
|
849
|
-
|
|
850
|
-
try {
|
|
851
|
-
// Валидация входных данных
|
|
852
|
-
if (!username || username.trim().length === 0) {
|
|
853
|
-
throw new Error('Username не может быть пустым');
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
const existingBot = await this.botRepository.findByUsername(username);
|
|
857
|
-
if (existingBot && existingBot.id !== botId) {
|
|
858
|
-
throw new Error(`Username "${username}" уже используется другим ботом (ID: ${existingBot.id})`);
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
const { encrypt } = require('../utils/crypto');
|
|
862
|
-
const updateData = { username };
|
|
863
|
-
|
|
864
|
-
if (password !== undefined && password !== null) {
|
|
865
|
-
if (password.trim().length === 0) {
|
|
866
|
-
throw new Error('Password не может быть пустым');
|
|
867
|
-
}
|
|
868
|
-
updateData.password = encrypt(password);
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
await this.botRepository.update(botId, updateData);
|
|
872
|
-
|
|
873
|
-
if (child.botConfig) {
|
|
874
|
-
child.botConfig.username = username;
|
|
875
|
-
if (password !== undefined && password !== null) {
|
|
876
|
-
child.botConfig.password = updateData.password;
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
this.logger.info({ botId, username }, 'Credentials обновлены в БД');
|
|
881
|
-
this.appendLog(botId, `[API] Credentials обновлены: username="${username}"`);
|
|
882
|
-
|
|
883
|
-
child.send({
|
|
884
|
-
type: 'credentials_operation_response',
|
|
885
|
-
requestId,
|
|
886
|
-
payload: {
|
|
887
|
-
success: true,
|
|
888
|
-
message: 'Credentials успешно обновлены в БД'
|
|
889
|
-
}
|
|
890
|
-
});
|
|
891
|
-
|
|
892
|
-
} catch (error) {
|
|
893
|
-
this.logger.error({ botId, error }, 'Ошибка обновления credentials');
|
|
894
|
-
this.appendLog(botId, `[API ERROR] Не удалось обновить credentials: ${error.message}`);
|
|
895
|
-
|
|
896
|
-
child.send({
|
|
897
|
-
type: 'credentials_operation_response',
|
|
898
|
-
requestId,
|
|
899
|
-
error: error.message
|
|
900
|
-
});
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
/**
|
|
905
|
-
* Обработчик рестарта бота
|
|
906
|
-
*/
|
|
907
|
-
async _handleRestartBot(botId, child, message) {
|
|
908
|
-
const { requestId } = message;
|
|
909
|
-
|
|
910
|
-
try {
|
|
911
|
-
this.logger.info({ botId }, 'Запрос на рестарт бота от плагина');
|
|
912
|
-
this.appendLog(botId, '[API] Получен запрос на рестарт бота от плагина');
|
|
913
|
-
|
|
914
|
-
const savedBotConfig = { ...child.botConfig };
|
|
915
|
-
|
|
916
|
-
child.send({
|
|
917
|
-
type: 'credentials_operation_response',
|
|
918
|
-
requestId,
|
|
919
|
-
payload: {
|
|
920
|
-
success: true,
|
|
921
|
-
message: 'Рестарт инициирован'
|
|
922
|
-
}
|
|
923
|
-
});
|
|
924
|
-
|
|
925
|
-
setTimeout(async () => {
|
|
926
|
-
try {
|
|
927
|
-
await this.restartBot(botId, savedBotConfig);
|
|
928
|
-
this.logger.info({ botId }, 'Бот успешно перезапущен');
|
|
929
|
-
} catch (error) {
|
|
930
|
-
this.logger.error({ botId, error }, 'Ошибка при рестарте бота');
|
|
931
|
-
this.appendLog(botId, `[API ERROR] Ошибка при рестарте: ${error.message}`);
|
|
932
|
-
}
|
|
933
|
-
}, 3000);
|
|
934
|
-
|
|
935
|
-
} catch (error) {
|
|
936
|
-
this.logger.error({ botId, error }, 'Ошибка инициализации рестарта');
|
|
937
|
-
|
|
938
|
-
child.send({
|
|
939
|
-
type: 'credentials_operation_response',
|
|
940
|
-
requestId,
|
|
941
|
-
error: error.message
|
|
942
|
-
});
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
/**
|
|
947
|
-
* Обработчик изменения credentials с автоматическим рестартом
|
|
948
|
-
*/
|
|
949
|
-
async _handleChangeCredentials(botId, child, message) {
|
|
950
|
-
const { requestId, payload } = message;
|
|
951
|
-
const { username, password } = payload;
|
|
952
|
-
|
|
953
|
-
try {
|
|
954
|
-
if (!username || username.trim().length === 0) {
|
|
955
|
-
throw new Error('Username не может быть пустым');
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
const existingBot = await this.botRepository.findByUsername(username);
|
|
959
|
-
if (existingBot && existingBot.id !== botId) {
|
|
960
|
-
throw new Error(`Username "${username}" уже используется другим ботом (ID: ${existingBot.id})`);
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
const { encrypt } = require('../utils/crypto');
|
|
964
|
-
const updateData = { username };
|
|
965
|
-
|
|
966
|
-
if (password !== undefined && password !== null) {
|
|
967
|
-
if (password.trim().length === 0) {
|
|
968
|
-
throw new Error('Password не может быть пустым');
|
|
969
|
-
}
|
|
970
|
-
updateData.password = encrypt(password);
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
await this.botRepository.update(botId, updateData);
|
|
974
|
-
|
|
975
|
-
if (child.botConfig) {
|
|
976
|
-
child.botConfig.username = username;
|
|
977
|
-
if (password !== undefined && password !== null) {
|
|
978
|
-
child.botConfig.password = updateData.password;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
const savedBotConfig = { ...child.botConfig };
|
|
983
|
-
|
|
984
|
-
this.logger.info({ botId, username }, 'Credentials обновлены, инициирован рестарт');
|
|
985
|
-
this.appendLog(botId, `[API] Credentials изменены: username="${username}". Выполняется рестарт...`);
|
|
986
|
-
|
|
987
|
-
child.send({
|
|
988
|
-
type: 'credentials_operation_response',
|
|
989
|
-
requestId,
|
|
990
|
-
payload: {
|
|
991
|
-
success: true,
|
|
992
|
-
message: 'Credentials обновлены, рестарт инициирован'
|
|
993
|
-
}
|
|
994
|
-
});
|
|
995
|
-
|
|
996
|
-
setTimeout(async () => {
|
|
997
|
-
try {
|
|
998
|
-
await this.restartBot(botId, savedBotConfig);
|
|
999
|
-
this.logger.info({ botId }, 'Бот успешно перезапущен с новыми credentials');
|
|
1000
|
-
} catch (error) {
|
|
1001
|
-
this.logger.error({ botId, error }, 'Ошибка при рестарте бота после изменения credentials');
|
|
1002
|
-
this.appendLog(botId, `[API ERROR] Ошибка при рестарте: ${error.message}`);
|
|
1003
|
-
}
|
|
1004
|
-
}, 3000);
|
|
1005
|
-
|
|
1006
|
-
} catch (error) {
|
|
1007
|
-
this.logger.error({ botId, error }, 'Ошибка изменения credentials');
|
|
1008
|
-
this.appendLog(botId, `[API ERROR] Не удалось изменить credentials: ${error.message}`);
|
|
1009
|
-
|
|
1010
|
-
child.send({
|
|
1011
|
-
type: 'credentials_operation_response',
|
|
1012
|
-
requestId,
|
|
1013
|
-
error: error.message
|
|
1014
|
-
});
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
426
|
}
|
|
1018
427
|
|
|
1019
|
-
module.exports = BotLifecycleService;
|
|
428
|
+
module.exports = BotLifecycleService;
|