From 8d4ef9858cecd56870c06082bf7aed9ab01958c0 Mon Sep 17 00:00:00 2001 From: Alexey Pelykh Date: Sat, 28 May 2022 16:03:37 +0200 Subject: [PATCH] Detect disconnected session (fix #2) --- package-lock.json | 5 ++++- src/PuppeteerCaptureBase.ts | 14 ++++++++++++++ ...PuppeteerCaptureViaHeadlessExperimental.test.ts | 13 +++++++++++++ src/PuppeteerCaptureViaHeadlessExperimental.ts | 2 +- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f3a233..f724b49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.0", "license": "MIT", "dependencies": { - "@ffmpeg-installer/ffmpeg": "^1.1.0", "async-mutex": "^0.3.2", "fluent-ffmpeg": "^2.1.2", "which": "^2.0.2" @@ -26,6 +25,10 @@ "ts-standard": "^11.0.0", "typescript": "^4.6.4" }, + "engines": { + "node": ">=14", + "npm": ">=7" + }, "optionalDependencies": { "@ffmpeg-installer/ffmpeg": "^1.1.0" }, diff --git a/src/PuppeteerCaptureBase.ts b/src/PuppeteerCaptureBase.ts index a5aa1d8..0a3489d 100644 --- a/src/PuppeteerCaptureBase.ts +++ b/src/PuppeteerCaptureBase.ts @@ -28,6 +28,7 @@ export abstract class PuppeteerCaptureBase extends EventEmitter implements Puppe protected readonly _frameInterval: number protected readonly _captureFrame: () => void protected readonly _onPageClose: () => void + protected readonly _onSessionDisconnected: () => void protected readonly _startStopMutex: Mutex protected _target: string | Writable | null protected _session: puppeteer.CDPSession | null @@ -62,6 +63,7 @@ export abstract class PuppeteerCaptureBase extends EventEmitter implements Puppe this._frameInterval = 1000.0 / this._options.fps this._captureFrame = this.captureFrame.bind(this) this._onPageClose = this.onPageClose.bind(this) + this._onSessionDisconnected = this.onSessionDisconnected.bind(this) this._startStopMutex = new Mutex() this._target = null this._session = null @@ -159,6 +161,7 @@ export abstract class PuppeteerCaptureBase extends EventEmitter implements Puppe } const session = await this._page.target().createCDPSession() + session.on('CDPSession.Disconnected', this._onSessionDisconnected) await this.configureSession(session) this._target = target @@ -284,6 +287,10 @@ export abstract class PuppeteerCaptureBase extends EventEmitter implements Puppe if (this._session != null) { await this.deconfigureSession(this._session) + this._session.off('CDPSession.Disconnected', this._onSessionDisconnected) + if (this._session.connection() != null) { + await this._session.detach() + } this._session = null } @@ -370,6 +377,13 @@ export abstract class PuppeteerCaptureBase extends EventEmitter implements Puppe .catch(() => { }) } + protected onSessionDisconnected (): void { + this._error = new Error('Session was disconnected') + this._startStopMutex.runExclusive(async () => await this._stop()) + .then(() => { }) + .catch(() => { }) + } + private static async findFfmpeg (): Promise { if (process.env.FFMPEG != null) { return process.env.FFMPEG diff --git a/src/PuppeteerCaptureViaHeadlessExperimental.test.ts b/src/PuppeteerCaptureViaHeadlessExperimental.test.ts index 3a5b69d..263eae5 100644 --- a/src/PuppeteerCaptureViaHeadlessExperimental.test.ts +++ b/src/PuppeteerCaptureViaHeadlessExperimental.test.ts @@ -116,3 +116,16 @@ test('that capture stops gracefully on page close', async () => { await capture.stop() }).rejects.toThrow('Page was closed') }) + +test('that capture stops gracefully on session connection drop', async () => { + browser = await launch({ args: PUPPETEER_LAUNCH_ARGS }) + const page = await browser.newPage() + const capture = new PuppeteerCaptureViaHeadlessExperimental(page) + const stream = new PassThrough() + await page.goto('https://google.com') + await capture.start(stream) + capture['_session']!.emit('CDPSession.Disconnected') // eslint-disable-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/dot-notation + await expect(async () => { + await capture.stop() + }).rejects.toThrow('Session was disconnected') +}) diff --git a/src/PuppeteerCaptureViaHeadlessExperimental.ts b/src/PuppeteerCaptureViaHeadlessExperimental.ts index ca2836c..3d3befc 100644 --- a/src/PuppeteerCaptureViaHeadlessExperimental.ts +++ b/src/PuppeteerCaptureViaHeadlessExperimental.ts @@ -31,7 +31,7 @@ export class PuppeteerCaptureViaHeadlessExperimental extends PuppeteerCaptureBas } protected override async deconfigureSession (session: puppeteer.CDPSession): Promise { - if (!this._page.isClosed()) { + if (session.connection() != null) { await session.send('HeadlessExperimental.disable') } }