From 156ba8147e69291d8c4cf17028231efc078ff895 Mon Sep 17 00:00:00 2001 From: sunlei Date: Wed, 24 Jun 2026 11:55:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AF=B9=E9=BD=90NapCat=20WebUI?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qqbot-napcat-webui-gateway.service.ts | 13 +++--- .../qqbot-napcat-webui-gateway.dto.ts | 6 ++- .../qqbot-napcat-webui-gateway.client.ts | 9 ++-- .../api-session.service.spec.ts | 43 ++++++++++++------- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/modules/qqbot/napcat/webui-gateway/application/qqbot-napcat-webui-gateway.service.ts b/src/modules/qqbot/napcat/webui-gateway/application/qqbot-napcat-webui-gateway.service.ts index 68ee42f..9613acc 100644 --- a/src/modules/qqbot/napcat/webui-gateway/application/qqbot-napcat-webui-gateway.service.ts +++ b/src/modules/qqbot/napcat/webui-gateway/application/qqbot-napcat-webui-gateway.service.ts @@ -151,10 +151,12 @@ export class QqbotNapcatWebuiGatewayService { const target = this.toGatewayTarget(runtime); const gatewaySession = await this.gatewayClient.createSession({ accountId: account.id, - accountName: account.name, + adminUserId: input.adminUserId, + clientIp: input.clientIp || undefined, containerId: runtime.id, containerName: runtime.name, selfId: account.selfId, + userAgent: input.userAgent || undefined, ...target, }); const webuiStatus = this.toWebuiStatus(runtime); @@ -216,14 +218,14 @@ export class QqbotNapcatWebuiGatewayService { /** * Converts private NapCat runtime fields into the Gateway client payload. * @param runtime - Primary NapCat runtime containing upstream URL, port, and WebUI token. - * @returns Internal-only Gateway target metadata. + * @returns Internal-only Gateway target metadata without exposing the raw WebUI port separately. */ private toGatewayTarget(runtime: QqbotNapcatRuntime) { - const targetBaseUrl = String(runtime.baseUrl || '').trim(); + const upstreamBaseUrl = String(runtime.baseUrl || '').trim(); const webuiToken = String(runtime.webuiToken || '').trim(); const webuiPort = Number(runtime.webuiPort); - if (!targetBaseUrl || !webuiToken || !Number.isFinite(webuiPort)) { + if (!upstreamBaseUrl || !webuiToken || !Number.isFinite(webuiPort)) { throwVbenError('NapCat WebUI 配置不完整'); } if (webuiPort <= 0) { @@ -231,8 +233,7 @@ export class QqbotNapcatWebuiGatewayService { } return { - targetBaseUrl, - webuiPort, + upstreamBaseUrl, webuiToken, }; } diff --git a/src/modules/qqbot/napcat/webui-gateway/contract/qqbot-napcat-webui-gateway.dto.ts b/src/modules/qqbot/napcat/webui-gateway/contract/qqbot-napcat-webui-gateway.dto.ts index 59bb03d..deb5f0f 100644 --- a/src/modules/qqbot/napcat/webui-gateway/contract/qqbot-napcat-webui-gateway.dto.ts +++ b/src/modules/qqbot/napcat/webui-gateway/contract/qqbot-napcat-webui-gateway.dto.ts @@ -38,8 +38,10 @@ export class QqbotNapcatWebuiSessionResponseDto { @ApiProperty({ type: QqbotNapcatWebuiSessionContainerDto }) container: QqbotNapcatWebuiSessionContainerDto; - @ApiProperty({ description: 'Gateway session expiry time in ISO format.' }) - expiresAt: string; + @ApiProperty({ + description: 'Gateway session expiry timestamp in milliseconds.', + }) + expiresAt: number; @ApiProperty({ description: 'Browser-safe iframe URL served by Gateway.' }) iframeUrl: string; diff --git a/src/modules/qqbot/napcat/webui-gateway/infrastructure/qqbot-napcat-webui-gateway.client.ts b/src/modules/qqbot/napcat/webui-gateway/infrastructure/qqbot-napcat-webui-gateway.client.ts index 7bc0781..6d07509 100644 --- a/src/modules/qqbot/napcat/webui-gateway/infrastructure/qqbot-napcat-webui-gateway.client.ts +++ b/src/modules/qqbot/napcat/webui-gateway/infrastructure/qqbot-napcat-webui-gateway.client.ts @@ -8,17 +8,18 @@ const DEFAULT_GATEWAY_TIMEOUT_MS = 5000; export type QqbotNapcatWebuiGatewayCreateSessionRequest = { accountId: string; - accountName: string; + adminUserId: string; + clientIp?: string; containerId: string; containerName: string; selfId: string; - targetBaseUrl: string; - webuiPort: number; + upstreamBaseUrl: string; + userAgent?: string; webuiToken: string; }; export type QqbotNapcatWebuiGatewaySessionResult = { - expiresAt: string; + expiresAt: number; iframeUrl: string; sessionId: string; }; diff --git a/test/modules/qqbot/napcat-webui-gateway/api-session.service.spec.ts b/test/modules/qqbot/napcat-webui-gateway/api-session.service.spec.ts index 4be5112..0ff9d48 100644 --- a/test/modules/qqbot/napcat-webui-gateway/api-session.service.spec.ts +++ b/test/modules/qqbot/napcat-webui-gateway/api-session.service.spec.ts @@ -18,6 +18,7 @@ jest.mock('axios'); const repoRoot = resolve(__dirname, '../../../..'); const requestMock = axios.request as jest.Mock; +const EXPIRES_AT_FIXTURE = 1782268000000; const INTERNAL_SECRET_FIXTURE = ['internal', 'secret'].join('-'); const WEBUI_TOKEN_FIXTURE = ['webui', 'token', 'fixture'].join('-'); @@ -87,7 +88,7 @@ describe('QqbotNapcatWebuiGatewayService', () => { webuiToken: WEBUI_TOKEN_FIXTURE, }; const gatewayResult = { - expiresAt: '2026-06-24T10:00:00.000Z', + expiresAt: EXPIRES_AT_FIXTURE, iframeUrl: '/napcat-webui-gateway/session/sess_1/', sessionId: 'sess_1', }; @@ -132,18 +133,19 @@ describe('QqbotNapcatWebuiGatewayService', () => { name: 'kt-qqbot-napcat-1914728559', webuiStatus: 'online', }, - expiresAt: '2026-06-24T10:00:00.000Z', + expiresAt: EXPIRES_AT_FIXTURE, iframeUrl: '/napcat-webui-gateway/session/sess_1/', sessionId: 'sess_1', }); expect(client.createSession).toHaveBeenCalledWith({ accountId: '1001', - accountName: '主机器人', + adminUserId: '3001', + clientIp: '127.0.0.1', containerId: '2001', containerName: 'kt-qqbot-napcat-1914728559', selfId: '1914728559', - targetBaseUrl: 'http://172.18.0.23:6099', - webuiPort: 6099, + upstreamBaseUrl: 'http://172.18.0.23:6099', + userAgent: 'jest-agent', webuiToken: WEBUI_TOKEN_FIXTURE, }); expect(serialized).not.toContain(WEBUI_TOKEN_FIXTURE); @@ -258,7 +260,7 @@ describe('QqbotNapcatWebuiGatewayClient', () => { requestMock.mockResolvedValue({ data: { data: { - expiresAt: '2026-06-24T10:00:00.000Z', + expiresAt: EXPIRES_AT_FIXTURE, iframeUrl: '/napcat-webui-gateway/session/sess_1/', sessionId: 'sess_1', }, @@ -277,20 +279,28 @@ describe('QqbotNapcatWebuiGatewayClient', () => { const result = await client.createSession({ accountId: '1001', - accountName: '主机器人', + adminUserId: '3001', + clientIp: '127.0.0.1', containerId: '2001', containerName: 'kt-qqbot-napcat-1914728559', selfId: '1914728559', - targetBaseUrl: 'http://172.18.0.23:6099', - webuiPort: 6099, + upstreamBaseUrl: 'http://172.18.0.23:6099', + userAgent: 'jest-agent', webuiToken: WEBUI_TOKEN_FIXTURE, }); expect(requestMock).toHaveBeenCalledWith({ - data: expect.objectContaining({ - targetBaseUrl: 'http://172.18.0.23:6099', + data: { + accountId: '1001', + adminUserId: '3001', + clientIp: '127.0.0.1', + containerId: '2001', + containerName: 'kt-qqbot-napcat-1914728559', + selfId: '1914728559', + upstreamBaseUrl: 'http://172.18.0.23:6099', + userAgent: 'jest-agent', webuiToken: WEBUI_TOKEN_FIXTURE, - }), + }, headers: { 'x-kt-gateway-secret': INTERNAL_SECRET_FIXTURE, }, @@ -299,7 +309,7 @@ describe('QqbotNapcatWebuiGatewayClient', () => { url: 'http://127.0.0.1:48086/internal/sessions', }); expect(result).toEqual({ - expiresAt: '2026-06-24T10:00:00.000Z', + expiresAt: EXPIRES_AT_FIXTURE, iframeUrl: '/napcat-webui-gateway/session/sess_1/', sessionId: 'sess_1', }); @@ -326,12 +336,13 @@ describe('QqbotNapcatWebuiGatewayClient', () => { try { await client.createSession({ accountId: '1001', - accountName: '主机器人', + adminUserId: '3001', + clientIp: '127.0.0.1', containerId: '2001', containerName: 'kt-qqbot-napcat-1914728559', selfId: '1914728559', - targetBaseUrl: 'http://172.18.0.23:6099', - webuiPort: 6099, + upstreamBaseUrl: 'http://172.18.0.23:6099', + userAgent: 'jest-agent', webuiToken: WEBUI_TOKEN_FIXTURE, }); } catch (error) {