UNPKG

3.06 kBPlain TextView Raw
1/**
2 * @license
3 * Copyright 2018 Google Inc.
4 * SPDX-License-Identifier: Apache-2.0
5 */
6import type {Protocol} from 'devtools-protocol';
7
8import {CDPSessionEvent, type CDPSession} from '../api/CDPSession.js';
9import type {Realm} from '../api/Realm.js';
10import {TargetType} from '../api/Target.js';
11import {WebWorker} from '../api/WebWorker.js';
12import {TimeoutSettings} from '../common/TimeoutSettings.js';
13import {debugError} from '../common/util.js';
14
15import {ExecutionContext} from './ExecutionContext.js';
16import {IsolatedWorld} from './IsolatedWorld.js';
17import {CdpJSHandle} from './JSHandle.js';
18
19/**
20 * @internal
21 */
22export type ConsoleAPICalledCallback = (
23 eventType: string,
24 handles: CdpJSHandle[],
25 trace?: Protocol.Runtime.StackTrace,
26) => void;
27
28/**
29 * @internal
30 */
31export type ExceptionThrownCallback = (
32 event: Protocol.Runtime.ExceptionThrownEvent,
33) => void;
34
35/**
36 * @internal
37 */
38export class CdpWebWorker extends WebWorker {
39 #world: IsolatedWorld;
40 #client: CDPSession;
41 readonly #id: string;
42 readonly #targetType: TargetType;
43
44 constructor(
45 client: CDPSession,
46 url: string,
47 targetId: string,
48 targetType: TargetType,
49 consoleAPICalled: ConsoleAPICalledCallback,
50 exceptionThrown: ExceptionThrownCallback,
51 ) {
52 super(url);
53 this.#id = targetId;
54 this.#client = client;
55 this.#targetType = targetType;
56 this.#world = new IsolatedWorld(this, new TimeoutSettings());
57
58 this.#client.once('Runtime.executionContextCreated', async event => {
59 this.#world.setContext(
60 new ExecutionContext(client, event.context, this.#world),
61 );
62 });
63 this.#world.emitter.on('consoleapicalled', async event => {
64 try {
65 return consoleAPICalled(
66 event.type,
67 event.args.map((object: Protocol.Runtime.RemoteObject) => {
68 return new CdpJSHandle(this.#world, object);
69 }),
70 event.stackTrace,
71 );
72 } catch (err) {
73 debugError(err);
74 }
75 });
76 this.#client.on('Runtime.exceptionThrown', exceptionThrown);
77 this.#client.once(CDPSessionEvent.Disconnected, () => {
78 this.#world.dispose();
79 });
80
81 // This might fail if the target is closed before we receive all execution contexts.
82 this.#client.send('Runtime.enable').catch(debugError);
83 }
84
85 mainRealm(): Realm {
86 return this.#world;
87 }
88
89 get client(): CDPSession {
90 return this.#client;
91 }
92
93 override async close(): Promise<void> {
94 switch (this.#targetType) {
95 case TargetType.SERVICE_WORKER:
96 case TargetType.SHARED_WORKER: {
97 // For service and shared workers we need to close the target and detach to allow
98 // the worker to stop.
99 await this.client.connection()?.send('Target.closeTarget', {
100 targetId: this.#id,
101 });
102 await this.client.connection()?.send('Target.detachFromTarget', {
103 sessionId: this.client.id(),
104 });
105 break;
106 }
107 default:
108 await this.evaluate(() => {
109 self.close();
110 });
111 }
112 }
113}