fix: 对齐NapCat WebUI会话契约
This commit is contained in:
parent
06eac5a01d
commit
156ba8147e
@ -151,10 +151,12 @@ export class QqbotNapcatWebuiGatewayService {
|
|||||||
const target = this.toGatewayTarget(runtime);
|
const target = this.toGatewayTarget(runtime);
|
||||||
const gatewaySession = await this.gatewayClient.createSession({
|
const gatewaySession = await this.gatewayClient.createSession({
|
||||||
accountId: account.id,
|
accountId: account.id,
|
||||||
accountName: account.name,
|
adminUserId: input.adminUserId,
|
||||||
|
clientIp: input.clientIp || undefined,
|
||||||
containerId: runtime.id,
|
containerId: runtime.id,
|
||||||
containerName: runtime.name,
|
containerName: runtime.name,
|
||||||
selfId: account.selfId,
|
selfId: account.selfId,
|
||||||
|
userAgent: input.userAgent || undefined,
|
||||||
...target,
|
...target,
|
||||||
});
|
});
|
||||||
const webuiStatus = this.toWebuiStatus(runtime);
|
const webuiStatus = this.toWebuiStatus(runtime);
|
||||||
@ -216,14 +218,14 @@ export class QqbotNapcatWebuiGatewayService {
|
|||||||
/**
|
/**
|
||||||
* Converts private NapCat runtime fields into the Gateway client payload.
|
* Converts private NapCat runtime fields into the Gateway client payload.
|
||||||
* @param runtime - Primary NapCat runtime containing upstream URL, port, and WebUI token.
|
* @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) {
|
private toGatewayTarget(runtime: QqbotNapcatRuntime) {
|
||||||
const targetBaseUrl = String(runtime.baseUrl || '').trim();
|
const upstreamBaseUrl = String(runtime.baseUrl || '').trim();
|
||||||
const webuiToken = String(runtime.webuiToken || '').trim();
|
const webuiToken = String(runtime.webuiToken || '').trim();
|
||||||
const webuiPort = Number(runtime.webuiPort);
|
const webuiPort = Number(runtime.webuiPort);
|
||||||
|
|
||||||
if (!targetBaseUrl || !webuiToken || !Number.isFinite(webuiPort)) {
|
if (!upstreamBaseUrl || !webuiToken || !Number.isFinite(webuiPort)) {
|
||||||
throwVbenError('NapCat WebUI 配置不完整');
|
throwVbenError('NapCat WebUI 配置不完整');
|
||||||
}
|
}
|
||||||
if (webuiPort <= 0) {
|
if (webuiPort <= 0) {
|
||||||
@ -231,8 +233,7 @@ export class QqbotNapcatWebuiGatewayService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
targetBaseUrl,
|
upstreamBaseUrl,
|
||||||
webuiPort,
|
|
||||||
webuiToken,
|
webuiToken,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,8 +38,10 @@ export class QqbotNapcatWebuiSessionResponseDto {
|
|||||||
@ApiProperty({ type: QqbotNapcatWebuiSessionContainerDto })
|
@ApiProperty({ type: QqbotNapcatWebuiSessionContainerDto })
|
||||||
container: QqbotNapcatWebuiSessionContainerDto;
|
container: QqbotNapcatWebuiSessionContainerDto;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Gateway session expiry time in ISO format.' })
|
@ApiProperty({
|
||||||
expiresAt: string;
|
description: 'Gateway session expiry timestamp in milliseconds.',
|
||||||
|
})
|
||||||
|
expiresAt: number;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Browser-safe iframe URL served by Gateway.' })
|
@ApiProperty({ description: 'Browser-safe iframe URL served by Gateway.' })
|
||||||
iframeUrl: string;
|
iframeUrl: string;
|
||||||
|
|||||||
@ -8,17 +8,18 @@ const DEFAULT_GATEWAY_TIMEOUT_MS = 5000;
|
|||||||
|
|
||||||
export type QqbotNapcatWebuiGatewayCreateSessionRequest = {
|
export type QqbotNapcatWebuiGatewayCreateSessionRequest = {
|
||||||
accountId: string;
|
accountId: string;
|
||||||
accountName: string;
|
adminUserId: string;
|
||||||
|
clientIp?: string;
|
||||||
containerId: string;
|
containerId: string;
|
||||||
containerName: string;
|
containerName: string;
|
||||||
selfId: string;
|
selfId: string;
|
||||||
targetBaseUrl: string;
|
upstreamBaseUrl: string;
|
||||||
webuiPort: number;
|
userAgent?: string;
|
||||||
webuiToken: string;
|
webuiToken: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type QqbotNapcatWebuiGatewaySessionResult = {
|
export type QqbotNapcatWebuiGatewaySessionResult = {
|
||||||
expiresAt: string;
|
expiresAt: number;
|
||||||
iframeUrl: string;
|
iframeUrl: string;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,6 +18,7 @@ jest.mock('axios');
|
|||||||
|
|
||||||
const repoRoot = resolve(__dirname, '../../../..');
|
const repoRoot = resolve(__dirname, '../../../..');
|
||||||
const requestMock = axios.request as jest.Mock;
|
const requestMock = axios.request as jest.Mock;
|
||||||
|
const EXPIRES_AT_FIXTURE = 1782268000000;
|
||||||
const INTERNAL_SECRET_FIXTURE = ['internal', 'secret'].join('-');
|
const INTERNAL_SECRET_FIXTURE = ['internal', 'secret'].join('-');
|
||||||
const WEBUI_TOKEN_FIXTURE = ['webui', 'token', 'fixture'].join('-');
|
const WEBUI_TOKEN_FIXTURE = ['webui', 'token', 'fixture'].join('-');
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ describe('QqbotNapcatWebuiGatewayService', () => {
|
|||||||
webuiToken: WEBUI_TOKEN_FIXTURE,
|
webuiToken: WEBUI_TOKEN_FIXTURE,
|
||||||
};
|
};
|
||||||
const gatewayResult = {
|
const gatewayResult = {
|
||||||
expiresAt: '2026-06-24T10:00:00.000Z',
|
expiresAt: EXPIRES_AT_FIXTURE,
|
||||||
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
||||||
sessionId: 'sess_1',
|
sessionId: 'sess_1',
|
||||||
};
|
};
|
||||||
@ -132,18 +133,19 @@ describe('QqbotNapcatWebuiGatewayService', () => {
|
|||||||
name: 'kt-qqbot-napcat-1914728559',
|
name: 'kt-qqbot-napcat-1914728559',
|
||||||
webuiStatus: 'online',
|
webuiStatus: 'online',
|
||||||
},
|
},
|
||||||
expiresAt: '2026-06-24T10:00:00.000Z',
|
expiresAt: EXPIRES_AT_FIXTURE,
|
||||||
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
||||||
sessionId: 'sess_1',
|
sessionId: 'sess_1',
|
||||||
});
|
});
|
||||||
expect(client.createSession).toHaveBeenCalledWith({
|
expect(client.createSession).toHaveBeenCalledWith({
|
||||||
accountId: '1001',
|
accountId: '1001',
|
||||||
accountName: '主机器人',
|
adminUserId: '3001',
|
||||||
|
clientIp: '127.0.0.1',
|
||||||
containerId: '2001',
|
containerId: '2001',
|
||||||
containerName: 'kt-qqbot-napcat-1914728559',
|
containerName: 'kt-qqbot-napcat-1914728559',
|
||||||
selfId: '1914728559',
|
selfId: '1914728559',
|
||||||
targetBaseUrl: 'http://172.18.0.23:6099',
|
upstreamBaseUrl: 'http://172.18.0.23:6099',
|
||||||
webuiPort: 6099,
|
userAgent: 'jest-agent',
|
||||||
webuiToken: WEBUI_TOKEN_FIXTURE,
|
webuiToken: WEBUI_TOKEN_FIXTURE,
|
||||||
});
|
});
|
||||||
expect(serialized).not.toContain(WEBUI_TOKEN_FIXTURE);
|
expect(serialized).not.toContain(WEBUI_TOKEN_FIXTURE);
|
||||||
@ -258,7 +260,7 @@ describe('QqbotNapcatWebuiGatewayClient', () => {
|
|||||||
requestMock.mockResolvedValue({
|
requestMock.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
data: {
|
data: {
|
||||||
expiresAt: '2026-06-24T10:00:00.000Z',
|
expiresAt: EXPIRES_AT_FIXTURE,
|
||||||
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
||||||
sessionId: 'sess_1',
|
sessionId: 'sess_1',
|
||||||
},
|
},
|
||||||
@ -277,20 +279,28 @@ describe('QqbotNapcatWebuiGatewayClient', () => {
|
|||||||
|
|
||||||
const result = await client.createSession({
|
const result = await client.createSession({
|
||||||
accountId: '1001',
|
accountId: '1001',
|
||||||
accountName: '主机器人',
|
adminUserId: '3001',
|
||||||
|
clientIp: '127.0.0.1',
|
||||||
containerId: '2001',
|
containerId: '2001',
|
||||||
containerName: 'kt-qqbot-napcat-1914728559',
|
containerName: 'kt-qqbot-napcat-1914728559',
|
||||||
selfId: '1914728559',
|
selfId: '1914728559',
|
||||||
targetBaseUrl: 'http://172.18.0.23:6099',
|
upstreamBaseUrl: 'http://172.18.0.23:6099',
|
||||||
webuiPort: 6099,
|
userAgent: 'jest-agent',
|
||||||
webuiToken: WEBUI_TOKEN_FIXTURE,
|
webuiToken: WEBUI_TOKEN_FIXTURE,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(requestMock).toHaveBeenCalledWith({
|
expect(requestMock).toHaveBeenCalledWith({
|
||||||
data: expect.objectContaining({
|
data: {
|
||||||
targetBaseUrl: 'http://172.18.0.23:6099',
|
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,
|
webuiToken: WEBUI_TOKEN_FIXTURE,
|
||||||
}),
|
},
|
||||||
headers: {
|
headers: {
|
||||||
'x-kt-gateway-secret': INTERNAL_SECRET_FIXTURE,
|
'x-kt-gateway-secret': INTERNAL_SECRET_FIXTURE,
|
||||||
},
|
},
|
||||||
@ -299,7 +309,7 @@ describe('QqbotNapcatWebuiGatewayClient', () => {
|
|||||||
url: 'http://127.0.0.1:48086/internal/sessions',
|
url: 'http://127.0.0.1:48086/internal/sessions',
|
||||||
});
|
});
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
expiresAt: '2026-06-24T10:00:00.000Z',
|
expiresAt: EXPIRES_AT_FIXTURE,
|
||||||
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
iframeUrl: '/napcat-webui-gateway/session/sess_1/',
|
||||||
sessionId: 'sess_1',
|
sessionId: 'sess_1',
|
||||||
});
|
});
|
||||||
@ -326,12 +336,13 @@ describe('QqbotNapcatWebuiGatewayClient', () => {
|
|||||||
try {
|
try {
|
||||||
await client.createSession({
|
await client.createSession({
|
||||||
accountId: '1001',
|
accountId: '1001',
|
||||||
accountName: '主机器人',
|
adminUserId: '3001',
|
||||||
|
clientIp: '127.0.0.1',
|
||||||
containerId: '2001',
|
containerId: '2001',
|
||||||
containerName: 'kt-qqbot-napcat-1914728559',
|
containerName: 'kt-qqbot-napcat-1914728559',
|
||||||
selfId: '1914728559',
|
selfId: '1914728559',
|
||||||
targetBaseUrl: 'http://172.18.0.23:6099',
|
upstreamBaseUrl: 'http://172.18.0.23:6099',
|
||||||
webuiPort: 6099,
|
userAgent: 'jest-agent',
|
||||||
webuiToken: WEBUI_TOKEN_FIXTURE,
|
webuiToken: WEBUI_TOKEN_FIXTURE,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user