feat(bridge): connect when a pipe is already up after load fails

A failed load used to stay in the error state. If the pipe is already
listening, connect instead, and keep retrying that case on later checks.
This commit is contained in:
DrSmoothl
2026-10-10 10:44:15 +08:00
parent 7496479782
commit effeb66554
3 changed files with 41 additions and 1 deletions
+3 -1
View File
@@ -309,7 +309,9 @@ export class HookManager {
this.runAutoLoad(session, autoLoad);
continue;
}
if ((session.status === 'connecting' || session.status === 'disconnected')
if ((session.status === 'connecting'
|| session.status === 'disconnected'
|| session.status === 'error')
&& this.pipeWatcher.isPipeLive(session.pid)) {
session.onPipeUp();
}
+9
View File
@@ -358,6 +358,15 @@ export class HookSession extends EventEmitter {
this._error = errMsg(error);
this.setStatus('error', this._error);
this.log.error('load failed: PID=%d err=%s', this.pid, this._error);
// The module can already be listening even when this call returns
// failure: another load left it resident, or it came up after the
// call returned. A live pipe still has the account state, so connect
// instead of staying on the failed load.
await this.pipeWatcher.tickNow?.();
if (!this.disposed && this.pipeWatcher.isPipeLive(this.pid)) {
this.log.info('PID=%d load failed but pipe is up; connecting', this.pid);
await this.reconcilePipeUp();
}
}
return this.toInfo();
}
@@ -205,6 +205,35 @@ describe('HookSession — runtime TRACE', () => {
}
});
it('connects when load fails but the pipe is already up', async () => {
let pipeLive = false;
const clients: FakeClient[] = [];
const session = new HookSession(7108, {
injector: {
inject: () => {
pipeLive = true;
throw new Error('component loading failed [COMPONENT_LOAD_FAILED]');
},
unload: () => undefined,
},
makeClient: () => {
const client = new FakeClient();
client.fireLogin('10001');
clients.push(client);
return client as unknown as QqHookClient;
},
pipeWatcher: {
isPipeLive: () => pipeLive,
tickNow: async () => undefined,
},
});
const info = await session.load();
expect(info.status).toBe('online');
expect(info.uin).toBe('10001');
expect(info.connected).toBe(true);
expect(clients).toHaveLength(1);
});
it('records login, disconnect, and process-gone only when state changes', async () => {
const entries: LogEntry[] = [];
setLogLevel('trace');