Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions packages/playwright-core/src/server/screencast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { ManualPromise } from '@isomorphic/manualPromise';
import { renderTitleForCall } from '@isomorphic/protocolFormatter';
import { debugLogger } from '@utils/debugLogger';
import { Page } from './page';
Expand All @@ -39,7 +40,7 @@ type ActionOptions = {

export class Screencast implements InstrumentationListener {
readonly page: Page;
private _clients = new Set<ScreencastClient>();
private _clients = new Map<ScreencastClient, ManualPromise<void>>();
private _actions: ActionOptions | undefined;
private _size: types.Size | undefined;
private _lastFrame: types.ScreencastFrame | undefined;
Expand All @@ -50,7 +51,7 @@ export class Screencast implements InstrumentationListener {
}

async handlePageOrContextClose() {
const clients = [...this._clients];
const clients = [...this._clients.keys()];
this._clients.clear();
for (const client of clients) {
if (client.gracefulClose)
Expand All @@ -59,7 +60,7 @@ export class Screencast implements InstrumentationListener {
}

dispose() {
for (const client of this._clients)
for (const client of this._clients.keys())
client.dispose();
this._clients.clear();
this.page.instrumentation.removeListener(this);
Expand All @@ -75,7 +76,7 @@ export class Screencast implements InstrumentationListener {

addClient(client: ScreencastClient): { size: types.Size } {
const isFirst = this._clients.size === 0;
this._clients.add(client);
this._clients.set(client, new ManualPromise<void>());
if (isFirst) {
this._startScreencast(client.size, client.quality);
} else if (this._lastFrame) {
Expand All @@ -92,9 +93,12 @@ export class Screencast implements InstrumentationListener {
}

removeClient(client: ScreencastClient) {
if (!this._clients.has(client))
const disconnected = this._clients.get(client);
if (!disconnected)
return;
this._clients.delete(client);
// A departing client must not block frame acks for the remaining clients.
disconnected.resolve();
if (!this._clients.size)
this._stopScreencast();
}
Expand Down Expand Up @@ -131,10 +135,11 @@ export class Screencast implements InstrumentationListener {
onScreencastFrame(frame: types.ScreencastFrame, ack?: () => void) {
this._lastFrame = frame;
const asyncResults: Promise<void>[] = [];
for (const client of this._clients) {
for (const [client, disconnected] of this._clients) {
const result = client.onFrame(frame);
if (result)
asyncResults.push(result);
if (!result)
continue;
asyncResults.push(Promise.race([result.catch(() => {}), disconnected]));
}
if (ack) {
// Ack when any client resolves (OR logic). This ensures that even if
Expand Down
Loading