Clean up CDP proxy client listeners
This commit is contained in:
parent
43714a2238
commit
dffd1ac180
|
|
@ -330,6 +330,28 @@ describe('CdpWsProxy', () => {
|
|||
})
|
||||
})
|
||||
|
||||
it('detaches client websocket listeners after client close', async () => {
|
||||
const client = await connect()
|
||||
const serverClient = (proxy as unknown as { client: WebSocket | null }).client
|
||||
expect(serverClient).toBeTruthy()
|
||||
const offSpy = vi.spyOn(serverClient!, 'off')
|
||||
|
||||
client.close()
|
||||
|
||||
const start = Date.now()
|
||||
while (
|
||||
(proxy as unknown as { client: WebSocket | null }).client &&
|
||||
Date.now() - start < 2_000
|
||||
) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 20))
|
||||
}
|
||||
|
||||
expect((proxy as unknown as { client: WebSocket | null }).client).toBeNull()
|
||||
const removedEvents = offSpy.mock.calls.map(([event]) => event)
|
||||
expect(removedEvents).toEqual(expect.arrayContaining(['message', 'close']))
|
||||
offSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('rejects inflight requests on stop', async () => {
|
||||
let resolveCommand: (v: unknown) => void
|
||||
mock.webContents.debugger.sendCommand.mockImplementation(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable max-lines -- Why: this proxy owns HTTP discovery, websocket client lifecycle, and CDP debugger forwarding together. */
|
||||
import { WebSocketServer, WebSocket } from 'ws'
|
||||
import { createServer, type Server, type IncomingMessage, type ServerResponse } from 'http'
|
||||
import type { WebContents } from 'electron'
|
||||
|
|
@ -9,6 +10,7 @@ export class CdpWsProxy {
|
|||
private httpServer: Server | null = null
|
||||
private wss: WebSocketServer | null = null
|
||||
private client: WebSocket | null = null
|
||||
private detachClientListeners: (() => void) | null = null
|
||||
private port = 0
|
||||
private debuggerMessageHandler: ((...args: unknown[]) => void) | null = null
|
||||
private debuggerDetachHandler: ((...args: unknown[]) => void) | null = null
|
||||
|
|
@ -39,16 +41,27 @@ export class CdpWsProxy {
|
|||
failStart(error)
|
||||
}
|
||||
this.wss.on('connection', (ws) => {
|
||||
if (this.client) {
|
||||
this.client.close()
|
||||
}
|
||||
this.closeClient()
|
||||
this.client = ws
|
||||
ws.on('message', (data) => this.handleClientMessage(ws, data.toString()))
|
||||
ws.on('close', () => {
|
||||
const onMessage = (data: WebSocket.RawData): void => {
|
||||
this.handleClientMessage(ws, data.toString())
|
||||
}
|
||||
const onClose = (): void => {
|
||||
detach()
|
||||
if (this.client === ws) {
|
||||
this.client = null
|
||||
}
|
||||
})
|
||||
}
|
||||
const detach = (): void => {
|
||||
ws.off('message', onMessage)
|
||||
ws.off('close', onClose)
|
||||
if (this.detachClientListeners === detach) {
|
||||
this.detachClientListeners = null
|
||||
}
|
||||
}
|
||||
this.detachClientListeners = detach
|
||||
ws.on('message', onMessage)
|
||||
ws.on('close', onClose)
|
||||
})
|
||||
this.httpServer.listen(0, '127.0.0.1', () => {
|
||||
this.httpServer?.removeListener('error', onListenError)
|
||||
|
|
@ -66,10 +79,7 @@ export class CdpWsProxy {
|
|||
|
||||
async stop(): Promise<void> {
|
||||
this.detachDebugger()
|
||||
if (this.client) {
|
||||
this.client.close()
|
||||
this.client = null
|
||||
}
|
||||
this.closeClient()
|
||||
if (this.wss) {
|
||||
this.wss.close()
|
||||
this.wss = null
|
||||
|
|
@ -84,6 +94,14 @@ export class CdpWsProxy {
|
|||
return this.port
|
||||
}
|
||||
|
||||
private closeClient(): void {
|
||||
const client = this.client
|
||||
this.detachClientListeners?.()
|
||||
this.detachClientListeners = null
|
||||
this.client = null
|
||||
client?.close()
|
||||
}
|
||||
|
||||
private send(payload: unknown, client = this.client): void {
|
||||
if (client?.readyState === WebSocket.OPEN) {
|
||||
client.send(JSON.stringify(payload))
|
||||
|
|
|
|||
Loading…
Reference in New Issue