chore: implement shared worker in bidi/core (#11907)

This commit is contained in:
jrandolf 2024-02-13 14:16:23 +01:00 committed by GitHub
parent 1bdae40ec8
commit 0b74d752fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 46 deletions

View File

@ -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<string, UserContext>();
readonly session: Session;
readonly #sharedWorkers = new Map<string, SharedWorkerRealm>();
// 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();

View File

@ -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<WindowRealm> {
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<BrowsingContext>(context => {

View File

@ -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<string, DedicatedWorkerRealm>;
shared: Map<string, SharedWorkerRealm>;
} = {
dedicated: new Map(),
shared: new Map(),
};
readonly #workers = new Map<string, DedicatedWorkerRealm>();
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<string, DedicatedWorkerRealm>();
readonly owners: Set<WindowRealm>;
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;
}
}