@myassis/gateway 1.0.25 → 1.0.27
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/dist/main.js +30 -18
- package/dist/services/ServiceManager.js +84 -13
- package/dist/services/session/Session.js +3 -3
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -209,38 +209,50 @@ else {
|
|
|
209
209
|
app.use(errorHandler_js_1.errorHandler);
|
|
210
210
|
// 创建 HTTP Server(而非 app.listen,以便挂载 WebSocket)
|
|
211
211
|
const server = http_1.default.createServer(app);
|
|
212
|
-
// 初始化 WebSocket 服务
|
|
213
|
-
WebSocketService_js_1.webSocketService.initialize(server);
|
|
214
|
-
// 启动任务调度器
|
|
215
|
-
TaskSchedulerService_js_1.taskSchedulerService.start();
|
|
216
212
|
// 端口自动顺延:被占用时自动尝试下一个端口
|
|
213
|
+
const configuredPort = index_js_1.appConfig.port;
|
|
214
|
+
let schedulerStarted = false;
|
|
215
|
+
let webSocketInitialized = false;
|
|
217
216
|
const startServer = (port) => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
index_js_1.appConfig.port = port;
|
|
221
|
-
if (port !== index_js_1.appConfig.port) {
|
|
222
|
-
logger.info(`Port ${index_js_1.appConfig.port} is in use, fallback to port ${port}`);
|
|
223
|
-
}
|
|
224
|
-
logger.info(`我的助手 Gateway Service running on port ${port}`);
|
|
225
|
-
}).on('error', (err) => {
|
|
217
|
+
const handleListenError = (err) => {
|
|
218
|
+
server.removeListener('error', handleListenError);
|
|
226
219
|
if (err.code === 'EADDRINUSE') {
|
|
227
220
|
const nextPort = port + 1;
|
|
228
|
-
if (nextPort <= (
|
|
221
|
+
if (nextPort <= (configuredPort + 10)) {
|
|
229
222
|
logger.warn(`Port ${port} is in use, trying ${nextPort}...`);
|
|
230
223
|
startServer(nextPort);
|
|
231
224
|
}
|
|
232
225
|
else {
|
|
233
|
-
logger.error(`All ports from ${
|
|
226
|
+
logger.error(`All ports from ${configuredPort} to ${configuredPort + 10} are in use`);
|
|
234
227
|
process.exit(1);
|
|
235
228
|
}
|
|
229
|
+
return;
|
|
236
230
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
231
|
+
logger.error(`Server error: ${err.message}`);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
};
|
|
234
|
+
server.once('error', handleListenError);
|
|
235
|
+
server.listen(port, () => {
|
|
236
|
+
server.removeListener('error', handleListenError);
|
|
237
|
+
if (port !== configuredPort) {
|
|
238
|
+
logger.info(`Port ${configuredPort} is in use, fallback to port ${port}`);
|
|
239
|
+
}
|
|
240
|
+
// 动态更新 appConfig.port(供 WebSocket 广播实际端口)
|
|
241
|
+
index_js_1.appConfig.port = port;
|
|
242
|
+
// HTTP Server 监听成功后再初始化 WebSocket,避免端口冲突时 WebSocketServer 误报 EADDRINUSE
|
|
243
|
+
if (!webSocketInitialized) {
|
|
244
|
+
WebSocketService_js_1.webSocketService.initialize(server);
|
|
245
|
+
webSocketInitialized = true;
|
|
246
|
+
}
|
|
247
|
+
// HTTP Server 启动成功后再启动任务调度器,避免端口占用时重复启动后台任务
|
|
248
|
+
if (!schedulerStarted) {
|
|
249
|
+
TaskSchedulerService_js_1.taskSchedulerService.start();
|
|
250
|
+
schedulerStarted = true;
|
|
240
251
|
}
|
|
252
|
+
logger.info(`我的助手 Gateway Service running on port ${port}`);
|
|
241
253
|
});
|
|
242
254
|
};
|
|
243
|
-
startServer(
|
|
255
|
+
startServer(configuredPort);
|
|
244
256
|
// 优雅关闭
|
|
245
257
|
process.on('SIGTERM', () => {
|
|
246
258
|
logger.info('收到 SIGTERM,正在关闭...');
|
|
@@ -378,21 +378,92 @@ async function updateService() {
|
|
|
378
378
|
return { success: true, message: `已是最新版本 ${check.currentVersion}` };
|
|
379
379
|
}
|
|
380
380
|
console.log(`发现新版本 ${check.latestVersion},正在更新...`);
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
381
|
+
if (isPackagedExe()) {
|
|
382
|
+
// pkg 环境:从 COS 下载对应平台的 exe
|
|
383
|
+
// ❗ 关键:不能在这里 stopService,进程本身即为服务进程,停止后后续代码不执行
|
|
384
|
+
// 方案:下载到临时文件后,spawn 一个独立延迟替换进程,本进程直接返回
|
|
385
|
+
const platform = process.platform === 'win32' ? 'win' : 'linux';
|
|
386
|
+
const isWin = platform === 'win';
|
|
387
|
+
const downloadUrl = isWin
|
|
388
|
+
? `https://myassis-1251246038.cos.ap-guangzhou.myqcloud.com/myassis-1251246038/installs/myassis-gateway-win.exe`
|
|
389
|
+
: `https://myassis-1251246038.cos.ap-guangzhou.myqcloud.com/myassis-1251246038/installs/myassis-gateway-linux`;
|
|
390
|
+
const currentExe = process.execPath;
|
|
391
|
+
const tmpExe = currentExe + '.new';
|
|
392
|
+
console.log(`正在下载 ${downloadUrl} ...`);
|
|
393
|
+
const response = await (0, axios_1.default)({
|
|
394
|
+
method: 'GET',
|
|
395
|
+
url: downloadUrl,
|
|
396
|
+
responseType: 'stream',
|
|
397
|
+
timeout: 300000,
|
|
398
|
+
});
|
|
399
|
+
const writeStream = fs_1.default.createWriteStream(tmpExe);
|
|
400
|
+
await new Promise((resolve, reject) => {
|
|
401
|
+
response.data.pipe(writeStream);
|
|
402
|
+
writeStream.on('finish', resolve);
|
|
403
|
+
writeStream.on('error', reject);
|
|
404
|
+
response.data.on('error', reject);
|
|
405
|
+
});
|
|
406
|
+
console.log('✅ 下载完成');
|
|
407
|
+
// 生成延迟替换脚本,spawn 为独立进程(当前进程 return 后不影响它)
|
|
408
|
+
if (isWin) {
|
|
409
|
+
const psScript = [
|
|
410
|
+
`Start-Sleep -Seconds 5`,
|
|
411
|
+
`Stop-Service -Name '${exports.SERVICE_NAME}' -ErrorAction SilentlyContinue`,
|
|
412
|
+
`Start-Sleep -Seconds 2`,
|
|
413
|
+
`while (Test-Path '${currentExe}') { try { Move-Item '${currentExe}' '${currentExe}.bak' -Force; break } catch { Start-Sleep -Seconds 1 } }`,
|
|
414
|
+
`Move-Item '${tmpExe}' '${currentExe}' -Force`,
|
|
415
|
+
`Start-Sleep -Seconds 1`,
|
|
416
|
+
`Start-Service -Name '${exports.SERVICE_NAME}'`,
|
|
417
|
+
`Remove-Item '${currentExe}.bak' -Force -ErrorAction SilentlyContinue`,
|
|
418
|
+
`Remove-Item '${tmpExe}' -Force -ErrorAction SilentlyContinue`,
|
|
419
|
+
].join('; ');
|
|
420
|
+
const args = ['-NoProfile', '-NonInteractive', '-Command', psScript];
|
|
421
|
+
const child = (0, child_process_1.spawn)('powershell.exe', args, {
|
|
422
|
+
detached: true,
|
|
423
|
+
stdio: 'ignore',
|
|
424
|
+
windowsHide: true,
|
|
425
|
+
});
|
|
426
|
+
child.unref();
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
// Linux: bash 延迟替换
|
|
430
|
+
const bashScript = [
|
|
431
|
+
'sleep 5',
|
|
432
|
+
`systemctl stop ${exports.SERVICE_NAME} 2>/dev/null || true`,
|
|
433
|
+
'sleep 2',
|
|
434
|
+
`mv -f '${currentExe}' '${currentExe}.bak' 2>/dev/null; true`,
|
|
435
|
+
`mv -f '${tmpExe}' '${currentExe}'`,
|
|
436
|
+
'sleep 1',
|
|
437
|
+
`systemctl start ${exports.SERVICE_NAME} 2>/dev/null || true`,
|
|
438
|
+
`rm -f '${currentExe}.bak' '${tmpExe}'`,
|
|
439
|
+
].join('; ');
|
|
440
|
+
const child = (0, child_process_1.spawn)('bash', ['-c', bashScript], {
|
|
441
|
+
detached: true,
|
|
442
|
+
stdio: 'ignore',
|
|
443
|
+
});
|
|
444
|
+
child.unref();
|
|
445
|
+
}
|
|
446
|
+
console.log('✅ 后台替换进程已启动,服务将在几秒后自动重启');
|
|
447
|
+
return { success: true, message: `更新成功: ${check.currentVersion} → ${check.latestVersion},服务正在后台替换...` };
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
// npm 环境
|
|
451
|
+
const { stdout, stderr } = await execAsync('npm install -g @myassis/gateway@latest', { timeout: 120000 });
|
|
452
|
+
if (stdout)
|
|
453
|
+
console.log(stdout);
|
|
454
|
+
if (stderr)
|
|
455
|
+
console.error(stderr);
|
|
456
|
+
console.log('✅ npm 更新完成');
|
|
457
|
+
const info = await getServiceInfo();
|
|
458
|
+
if (info.installed) {
|
|
459
|
+
console.log('正在重启服务...');
|
|
460
|
+
const r = await restartService();
|
|
461
|
+
if (!r.success) {
|
|
462
|
+
return { success: false, message: `更新成功但服务重启失败: ${r.message}` };
|
|
463
|
+
}
|
|
393
464
|
}
|
|
465
|
+
return { success: true, message: `更新成功: ${check.currentVersion} → ${check.latestVersion}` };
|
|
394
466
|
}
|
|
395
|
-
return { success: true, message: `更新成功: ${check.currentVersion} → ${check.latestVersion}` };
|
|
396
467
|
}
|
|
397
468
|
catch (err) {
|
|
398
469
|
return { success: false, message: `更新失败: ${err.message}` };
|
|
@@ -501,6 +501,9 @@ class Session {
|
|
|
501
501
|
}
|
|
502
502
|
};
|
|
503
503
|
const toolCalls = [];
|
|
504
|
+
// 获取本地工具定义
|
|
505
|
+
const tools = (0, index_js_1.getToolDefinitions)();
|
|
506
|
+
const models = (await dataService_js_1.modelsService.list(token)).data.map(x => (0, models_js_1.toModel)(x));
|
|
504
507
|
// 递归处理函数(支持多轮工具调用)
|
|
505
508
|
const processModelResponse = async () => {
|
|
506
509
|
if (!this.abortController || !this.abortController.signal || this.abortController.signal.aborted) {
|
|
@@ -547,9 +550,6 @@ class Session {
|
|
|
547
550
|
}
|
|
548
551
|
}
|
|
549
552
|
}
|
|
550
|
-
// 获取本地工具定义
|
|
551
|
-
const tools = (0, index_js_1.getToolDefinitions)();
|
|
552
|
-
const models = (await dataService_js_1.modelsService.list(token)).data.map(x => (0, models_js_1.toModel)(x));
|
|
553
553
|
// 使用 LLMClient 进行流式调用
|
|
554
554
|
if (!this.abortController || !this.abortController.signal || this.abortController.signal.aborted) {
|
|
555
555
|
throw Error('aborted');
|