1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 * Worker debugger script that listens for requests to start a `DevToolsServer` for a
11 * worker in a process. Loaded into a specific worker during worker-connector.js'
12 * `connectToWorker` which is called from the same process as the worker.
15 // This function is used to do remote procedure calls from the worker to the
16 // main thread. It is exposed as a built-in global to every module by the
17 // worker loader. To make sure the worker loader can access it, it needs to be
18 // defined before loading the worker loader script below.
20 this.rpc = function (method
, ...params
) {
21 return new Promise((resolve
, reject
) => {
23 this.addEventListener("message", function onMessageForRpc(event
) {
24 const packet
= JSON
.parse(event
.data
);
25 if (packet
.type
!== "rpc" || packet
.id
!== id
) {
31 resolve(packet
.result
);
33 this.removeEventListener("message", onMessageForRpc
);
47 const { worker
} = ChromeUtils
.importESModule(
48 "resource://devtools/shared/loader/worker-loader.sys.mjs",
52 const { WorkerTargetActor
} = worker
.require(
53 "resource://devtools/server/actors/targets/worker.js"
55 const { DevToolsServer
} = worker
.require(
56 "resource://devtools/server/devtools-server.js"
59 DevToolsServer
.createRootActor = function () {
60 throw new Error("Should never get here!");
63 // This file is only instanciated once for a given WorkerDebugger, which means that
64 // multiple toolbox could end up using the same instance of this script. In order to handle
65 // that, we handle a Map of the different connections, keyed by forwarding prefix.
66 const connections
= new Map();
68 this.addEventListener("message", async
function (event
) {
69 const packet
= JSON
.parse(event
.data
);
70 switch (packet
.type
) {
72 const { forwardingPrefix
} = packet
;
74 // Force initializing the server each time on connect
75 // as it may have been destroyed by a previous, now closed toolbox.
76 // Once the last connection drops, the server auto destroy itself.
77 DevToolsServer
.init();
79 // Step 3: Create a connection to the parent.
80 const connection
= DevToolsServer
.connectToParent(forwardingPrefix
, this);
82 // Step 4: Create a WorkerTarget actor.
83 const workerTargetActor
= new WorkerTargetActor(
86 packet
.workerDebuggerData
,
87 packet
.options
.sessionContext
89 // Make the worker manage itself so it is put in a Pool and assigned an actorID.
90 workerTargetActor
.manage(workerTargetActor
);
92 // Step 5: Send a response packet to the parent to notify
93 // it that a connection has been established.
94 connections
.set(forwardingPrefix
, {
99 // Immediately notify about the target actor form,
100 // so that we can emit RDP events from the target actor
101 // and have them correctly routed up to the frontend.
102 // The target front has to be first created by receiving its form
103 // before being able to receive RDP events.
108 workerTargetForm
: workerTargetActor
.form(),
112 // We might receive data to watch.
113 if (packet
.options
.sessionData
) {
115 for (const [type
, entries
] of Object
.entries(
116 packet
.options
.sessionData
119 workerTargetActor
.addOrSetSessionDataEntry(
127 await Promise
.all(promises
);
130 // Finally, notify when we are done processing session data
131 // We are processing breakpoints, which means we can release the execution of the worker
132 // from the main thread via `WorkerDebugger.setDebuggerReady(true)`
133 postMessage(JSON
.stringify({ type
: "session-data-processed" }));
137 case "add-or-set-session-data-entry":
139 .get(packet
.forwardingPrefix
)
140 .workerTargetActor
.addOrSetSessionDataEntry(
141 packet
.dataEntryType
,
145 postMessage(JSON
.stringify({ type
: "session-data-entry-added-or-set" }));
148 case "remove-session-data-entry":
150 .get(packet
.forwardingPrefix
)
151 .workerTargetActor
.removeSessionDataEntry(
152 packet
.dataEntryType
,
158 // This will destroy the associate WorkerTargetActor (and the actors it manages).
159 if (connections
.has(packet
.forwardingPrefix
)) {
160 connections
.get(packet
.forwardingPrefix
).connection
.close();
161 connections
.delete(packet
.forwardingPrefix
);