fix: 复用已有NapCat设备身份
This commit is contained in:
parent
ebf63f892f
commit
01a7e79bd1
@ -129,9 +129,17 @@ export class QqbotNapcatContainerService {
|
||||
}
|
||||
|
||||
try {
|
||||
const deviceIdentity = await this.resolveRuntimeDeviceIdentity(
|
||||
container,
|
||||
account,
|
||||
);
|
||||
await this.createRemoteDockerContainer({
|
||||
account,
|
||||
dataDir: container.dataDir || `${this.getRootDir()}/${container.name}`,
|
||||
dataDir:
|
||||
deviceIdentity?.dataDir ||
|
||||
container.dataDir ||
|
||||
`${this.getRootDir()}/${container.name}`,
|
||||
deviceIdentity,
|
||||
image: container.image,
|
||||
loginPassword: options.clearLoginPassword
|
||||
? undefined
|
||||
@ -160,6 +168,36 @@ export class QqbotNapcatContainerService {
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveRuntimeDeviceIdentity(
|
||||
container: QqbotNapcatContainer,
|
||||
selfId: string,
|
||||
): Promise<NapcatDockerDeviceOptions | undefined> {
|
||||
if (
|
||||
!this.deviceIdentityService ||
|
||||
!container.id ||
|
||||
typeof this.bindingRepository.findOne !== 'function'
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const binding = await this.bindingRepository.findOne({
|
||||
where: {
|
||||
bindStatus: 'bound',
|
||||
containerId: container.id,
|
||||
isDeleted: false,
|
||||
isPrimary: true,
|
||||
},
|
||||
});
|
||||
if (!binding?.accountId) return undefined;
|
||||
|
||||
const identity = await this.deviceIdentityService.resolveForAccount({
|
||||
accountId: binding.accountId,
|
||||
containerId: container.id,
|
||||
selfId,
|
||||
});
|
||||
return toNapcatDockerDeviceOptions(identity);
|
||||
}
|
||||
|
||||
async tryAutoLogin(
|
||||
container: QqbotNapcatContainer,
|
||||
options: NapcatLoginEnvOptions,
|
||||
|
||||
@ -270,4 +270,95 @@ describe('NapCat device identity persistence', () => {
|
||||
expect(createScript).toContain('--mac-address "$NAPCAT_MAC_ADDRESS"');
|
||||
expect(createScript).toContain('-v "$MACHINE_ID_PATH:/etc/machine-id:ro"');
|
||||
});
|
||||
|
||||
it('reuses persisted device identity when rebuilding an existing account container login env', async () => {
|
||||
const identityRepository = createIdentityRepository();
|
||||
const identityService = new NapcatDeviceIdentityService(
|
||||
identityRepository as any,
|
||||
createIdentityConfig(),
|
||||
);
|
||||
const identity = await identityService.resolveForAccount({
|
||||
accountId: 'account-10001',
|
||||
containerId: 'container-1',
|
||||
selfId: '10001',
|
||||
});
|
||||
const bindingRepository = {
|
||||
findOne: jest.fn().mockResolvedValue({
|
||||
accountId: 'account-10001',
|
||||
containerId: 'container-1',
|
||||
isDeleted: false,
|
||||
isPrimary: true,
|
||||
}),
|
||||
};
|
||||
const containerRepository = {
|
||||
createQueryBuilder: jest.fn(() => ({
|
||||
addSelect: jest.fn().mockReturnThis(),
|
||||
andWhere: jest.fn().mockReturnThis(),
|
||||
getOne: jest.fn().mockResolvedValue({
|
||||
dataDir: identity.dataDir,
|
||||
id: 'container-1',
|
||||
image: 'mlikiowa/napcat-docker:latest',
|
||||
name: 'kt-qqbot-napcat-10001',
|
||||
reverseWsUrl: 'ws://127.0.0.1:48085/qqbot/onebot/reverse',
|
||||
webuiPort: 6100,
|
||||
webuiToken: 'token-x',
|
||||
}),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
})),
|
||||
update: jest.fn(),
|
||||
};
|
||||
const containerService = new QqbotNapcatContainerService(
|
||||
{
|
||||
get: jest.fn((key: string, defaultValue?: string) => {
|
||||
const values: Record<string, string> = {
|
||||
QQBOT_NAPCAT_CONTAINER_MODE: 'ssh',
|
||||
QQBOT_NAPCAT_CONTAINER_PREFIX: 'kt-qqbot-napcat',
|
||||
QQBOT_NAPCAT_IMAGE: 'mlikiowa/napcat-docker:latest',
|
||||
QQBOT_NAPCAT_ROOT: '/vol1/docker/kt-qqbot/napcat-instances',
|
||||
QQBOT_NAPCAT_SSH_TARGET: 'nas',
|
||||
};
|
||||
return values[key] || defaultValue || '';
|
||||
}),
|
||||
} as any,
|
||||
containerRepository as any,
|
||||
bindingRepository as any,
|
||||
new ToolsService(),
|
||||
identityService,
|
||||
) as any;
|
||||
containerService.runProcess = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
stderr: '',
|
||||
stdout: 'ACCOUNT=10001\nNAPCAT_QUICK_PASSWORD=old-password\n',
|
||||
})
|
||||
.mockResolvedValueOnce({ stderr: '', stdout: '' })
|
||||
.mockResolvedValueOnce({ stderr: '', stdout: 'ACCOUNT=10001\n' });
|
||||
|
||||
const recreated = await containerService.ensureRuntimeLoginEnv(
|
||||
{ id: 'container-1', name: 'kt-qqbot-napcat-10001' },
|
||||
{
|
||||
clearLoginPassword: true,
|
||||
selfId: '10001',
|
||||
},
|
||||
);
|
||||
|
||||
expect(recreated).toEqual({ changed: true, ok: true });
|
||||
expect(bindingRepository.findOne).toHaveBeenCalledWith({
|
||||
where: {
|
||||
bindStatus: 'bound',
|
||||
containerId: 'container-1',
|
||||
isDeleted: false,
|
||||
isPrimary: true,
|
||||
},
|
||||
});
|
||||
const createScript = containerService.runProcess.mock.calls[1][2];
|
||||
expect(createScript).toContain(`NAPCAT_HOSTNAME='${identity.hostname}'`);
|
||||
expect(createScript).toContain(
|
||||
`NAPCAT_MAC_ADDRESS='${identity.macAddress}'`,
|
||||
);
|
||||
expect(createScript).toContain(`MACHINE_ID_PATH='${identity.machineIdPath}'`);
|
||||
expect(createScript).toContain('--hostname "$NAPCAT_HOSTNAME"');
|
||||
expect(createScript).toContain('--mac-address "$NAPCAT_MAC_ADDRESS"');
|
||||
expect(createScript).toContain('-v "$MACHINE_ID_PATH:/etc/machine-id:ro"');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user