From 0b74d752fb24f6bc7089fa354b64004994b3f2d4 Mon Sep 17 00:00:00 2001 From: jrandolf <101637635+jrandolf@users.noreply.github.com> Date: Tue, 13 Feb 2024 14:16:23 +0100 Subject: [PATCH] chore: implement shared worker in `bidi/core` (#11907) --- .../puppeteer-core/src/bidi/core/Browser.ts | 11 ++-- .../src/bidi/core/BrowsingContext.ts | 25 ++++++++-- .../puppeteer-core/src/bidi/core/Realm.ts | 50 ++++--------------- 3 files changed, 40 insertions(+), 46 deletions(-) diff --git a/packages/puppeteer-core/src/bidi/core/Browser.ts b/packages/puppeteer-core/src/bidi/core/Browser.ts index c845f66b79f..efeabc3a590 100644 --- a/packages/puppeteer-core/src/bidi/core/Browser.ts +++ b/packages/puppeteer-core/src/bidi/core/Browser.ts @@ -11,7 +11,7 @@ import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {BrowsingContext} from './BrowsingContext.js'; -import type {SharedWorkerRealm} from './Realm.js'; +import {SharedWorkerRealm} from './Realm.js'; import type {Session} from './Session.js'; import {UserContext} from './UserContext.js'; @@ -57,6 +57,7 @@ export class Browser extends EventEmitter<{ readonly #disposables = new DisposableStack(); readonly #userContexts = new Map(); readonly session: Session; + readonly #sharedWorkers = new Map(); // keep-sorted end private constructor(session: Session) { @@ -75,9 +76,13 @@ export class Browser extends EventEmitter<{ }); sessionEmitter.on('script.realmCreated', info => { - if (info.type === 'shared-worker') { - // TODO: Create a SharedWorkerRealm. + if (info.type !== 'shared-worker') { + return; } + this.#sharedWorkers.set( + info.realm, + SharedWorkerRealm.from(this, info.realm, info.origin) + ); }); await this.#syncUserContexts(); diff --git a/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts b/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts index 89ffae5ab32..711018bc307 100644 --- a/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts +++ b/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts @@ -12,6 +12,7 @@ import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {AddPreloadScriptOptions} from './Browser.js'; import {Navigation} from './Navigation.js'; +import type {DedicatedWorkerRealm} from './Realm.js'; import {WindowRealm} from './Realm.js'; import {Request} from './Request.js'; import type {UserContext} from './UserContext.js'; @@ -103,6 +104,11 @@ export class BrowsingContext extends EventEmitter<{ DOMContentLoaded: void; /** Emitted whenever the frame emits `load` */ load: void; + /** Emitted whenever a dedicated worker is created */ + worker: { + /** The realm for the new dedicated worker */ + realm: DedicatedWorkerRealm; + }; }> { static from( userContext: UserContext, @@ -143,7 +149,7 @@ export class BrowsingContext extends EventEmitter<{ this.userContext = context; // keep-sorted end - this.defaultRealm = WindowRealm.from(this); + this.defaultRealm = this.#createWindowRealm(); } #initialize() { @@ -283,7 +289,12 @@ export class BrowsingContext extends EventEmitter<{ return this.closed; } get realms(): Iterable { - return this.#realms.values(); + // eslint-disable-next-line @typescript-eslint/no-this-alias -- Required + const self = this; + return (function* () { + yield self.defaultRealm; + yield* self.#realms.values(); + })(); } get top(): BrowsingContext { let context = this as BrowsingContext; @@ -297,6 +308,14 @@ export class BrowsingContext extends EventEmitter<{ } // keep-sorted end + #createWindowRealm(sandbox?: string) { + const realm = WindowRealm.from(this, sandbox); + realm.on('worker', realm => { + this.emit('worker', {realm}); + }); + return realm; + } + @inertIfDisposed private dispose(reason?: string): void { this.#reason = reason; @@ -444,7 +463,7 @@ export class BrowsingContext extends EventEmitter<{ return context.#reason!; }) createWindowRealm(sandbox: string): WindowRealm { - return WindowRealm.from(this, sandbox); + return this.#createWindowRealm(sandbox); } @throwIfDisposed(context => { diff --git a/packages/puppeteer-core/src/bidi/core/Realm.ts b/packages/puppeteer-core/src/bidi/core/Realm.ts index 18a5b3c722d..c0aa37fb85c 100644 --- a/packages/puppeteer-core/src/bidi/core/Realm.ts +++ b/packages/puppeteer-core/src/bidi/core/Realm.ts @@ -10,6 +10,7 @@ import {EventEmitter} from '../../common/EventEmitter.js'; import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; +import type {Browser} from './Browser.js'; import type {BrowsingContext} from './BrowsingContext.js'; import type {Session} from './Session.js'; @@ -145,13 +146,7 @@ export class WindowRealm extends Realm { readonly sandbox?: string; // keep-sorted end - readonly #workers: { - dedicated: Map; - shared: Map; - } = { - dedicated: new Map(), - shared: new Map(), - }; + readonly #workers = new Map(); private constructor(context: BrowsingContext, sandbox?: string) { super('', ''); @@ -191,32 +186,16 @@ export class WindowRealm extends Realm { } const realm = DedicatedWorkerRealm.from(this, info.realm, info.origin); - this.#workers.dedicated.set(realm.id, realm); + this.#workers.set(realm.id, realm); const realmEmitter = this.disposables.use(new EventEmitter(realm)); realmEmitter.once('destroyed', () => { realmEmitter.removeAllListeners(); - this.#workers.dedicated.delete(realm.id); + this.#workers.delete(realm.id); }); this.emit('worker', realm); }); - - this.browsingContext.userContext.browser.on('sharedworker', ({realm}) => { - if (!realm.owners.has(this)) { - return; - } - - this.#workers.shared.set(realm.id, realm); - - const realmEmitter = this.disposables.use(new EventEmitter(realm)); - realmEmitter.once('destroyed', () => { - realmEmitter.removeAllListeners(); - this.#workers.shared.delete(realm.id); - }); - - this.emit('sharedworker', realm); - }); } override get session(): Session { @@ -302,28 +281,20 @@ export class DedicatedWorkerRealm extends Realm { * @internal */ export class SharedWorkerRealm extends Realm { - static from( - owners: [WindowRealm, ...WindowRealm[]], - id: string, - origin: string - ): SharedWorkerRealm { - const realm = new SharedWorkerRealm(owners, id, origin); + static from(browser: Browser, id: string, origin: string): SharedWorkerRealm { + const realm = new SharedWorkerRealm(browser, id, origin); realm.#initialize(); return realm; } // keep-sorted start readonly #workers = new Map(); - readonly owners: Set; + readonly browser: Browser; // keep-sorted end - private constructor( - owners: [WindowRealm, ...WindowRealm[]], - id: string, - origin: string - ) { + private constructor(browser: Browser, id: string, origin: string) { super(id, origin); - this.owners = new Set(owners); + this.browser = browser; } #initialize(): void { @@ -355,7 +326,6 @@ export class SharedWorkerRealm extends Realm { } override get session(): Session { - // SAFETY: At least one owner will exist. - return this.owners.values().next().value.session; + return this.browser.session; } }