Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / devtools / server / startup / worker.js
blob6ed880eb28c84b8ca59840f68af5fc1c2cf4a5eb
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/. */
5 "use strict";
7 /* global global */
9 /*
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.
19 let nextId = 0;
20 this.rpc = function (method, ...params) {
21 return new Promise((resolve, reject) => {
22 const id = nextId++;
23 this.addEventListener("message", function onMessageForRpc(event) {
24 const packet = JSON.parse(event.data);
25 if (packet.type !== "rpc" || packet.id !== id) {
26 return;
28 if (packet.error) {
29 reject(packet.error);
30 } else {
31 resolve(packet.result);
33 this.removeEventListener("message", onMessageForRpc);
34 });
36 postMessage(
37 JSON.stringify({
38 type: "rpc",
39 method,
40 params,
41 id,
44 });
45 }.bind(this);
47 const { worker } = ChromeUtils.importESModule(
48 "resource://devtools/shared/loader/worker-loader.sys.mjs",
49 { global: "current" }
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) {
71 case "connect":
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(
84 connection,
85 global,
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, {
95 connection,
96 workerTargetActor,
97 });
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.
104 postMessage(
105 JSON.stringify({
106 type: "connected",
107 forwardingPrefix,
108 workerTargetForm: workerTargetActor.form(),
112 // We might receive data to watch.
113 if (packet.options.sessionData) {
114 const promises = [];
115 for (const [type, entries] of Object.entries(
116 packet.options.sessionData
117 )) {
118 promises.push(
119 workerTargetActor.addOrSetSessionDataEntry(
120 type,
121 entries,
122 false,
123 "set"
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" }));
135 break;
137 case "add-or-set-session-data-entry":
138 await connections
139 .get(packet.forwardingPrefix)
140 .workerTargetActor.addOrSetSessionDataEntry(
141 packet.dataEntryType,
142 packet.entries,
143 packet.updateType
145 postMessage(JSON.stringify({ type: "session-data-entry-added-or-set" }));
146 break;
148 case "remove-session-data-entry":
149 await connections
150 .get(packet.forwardingPrefix)
151 .workerTargetActor.removeSessionDataEntry(
152 packet.dataEntryType,
153 packet.entries
155 break;
157 case "disconnect":
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);
163 break;