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/. */
7 var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js");
9 loader.lazyRequireGetter(
11 "MainThreadWorkerDebuggerTransport",
12 "resource://devtools/shared/transport/worker-transport.js",
17 * Start a DevTools server in a worker and add it as a child server for a given active connection.
19 * @params {DevToolsConnection} connection
20 * @params {WorkerDebugger} dbg: The WorkerDebugger we want to create a target actor for.
21 * @params {String} forwardingPrefix: The prefix that will be used to forward messages
22 * to the DevToolsServer on the worker thread.
23 * @params {Object} options: An option object that will be passed with the "connect" packet.
24 * @params {Object} options.sessionData: The sessionData object that will be passed to the
25 * worker target actor.
27 function connectToWorker(connection, dbg, forwardingPrefix, options) {
28 return new Promise((resolve, reject) => {
29 if (!DevToolsUtils.isWorkerDebuggerAlive(dbg)) {
34 // Step 1: Ensure the worker debugger is initialized.
35 if (!dbg.isInitialized) {
36 dbg.initialize("resource://devtools/server/startup/worker.js");
38 // Create a listener for rpc requests from the worker debugger. Only do
39 // this once, when the worker debugger is first initialized, rather than
40 // for each connection.
43 dbg.removeListener(listener);
46 onMessage: message => {
47 message = JSON.parse(message);
48 if (message.type !== "rpc") {
49 if (message.type == "session-data-processed") {
50 // The thread actor has finished processing session data, including breakpoints.
51 // Allow content to begin executing in the worker and possibly hit early breakpoints.
52 dbg.setDebuggerReady(true);
60 fetch: DevToolsUtils.fetch,
63 throw Error("Unknown method: " + message.method);
66 return method.apply(undefined, message.params);
93 dbg.addListener(listener);
96 if (!DevToolsUtils.isWorkerDebuggerAlive(dbg)) {
101 // WorkerDebugger.url isn't always an absolute URL.
102 // Use the related document URL in order to make it absolute.
103 const absoluteURL = dbg.window?.location?.href
104 ? new URL(dbg.url, dbg.window.location.href).href
107 // Step 2: Send a connect request to the worker debugger.
113 workerDebuggerData: {
117 // We don't have access to Services.prefs in Worker thread, so pass its value
119 workerConsoleApiMessagesDispatchedToMainThread:
120 Services.prefs.getBoolPref(
121 "dom.worker.console.dispatch_events_to_main_thread"
127 // Steps 3-5 are performed on the worker thread (see worker.js).
129 // Step 6: Wait for a connection response from the worker debugger.
132 dbg.removeListener(listener);
137 onMessage: message => {
138 message = JSON.parse(message);
140 message.type !== "connected" ||
141 message.forwardingPrefix !== forwardingPrefix
146 // The initial connection message has been received, don't
147 // need to listen any longer
148 dbg.removeListener(listener);
150 // Step 7: Create a transport for the connection to the worker.
151 const transport = new MainThreadWorkerDebuggerTransport(
157 onTransportClosed: () => {
158 if (DevToolsUtils.isWorkerDebuggerAlive(dbg)) {
159 // If the worker happens to be shutting down while we are trying
160 // to close the connection, there is a small interval during
161 // which no more runnables can be dispatched to the worker, but
162 // the worker debugger has not yet been closed. In that case,
163 // the call to postMessage below will fail. The onTransportClosed hook on
164 // DebuggerTransport is not supposed to throw exceptions, so we
165 // need to make sure to catch these early.
174 // We can safely ignore these exceptions. The only time the
175 // call to postMessage can fail is if the worker is either
176 // shutting down, or has finished shutting down. In both
177 // cases, there is nothing to clean up, so we don't care
178 // whether this message arrives or not.
182 connection.cancelForwarding(forwardingPrefix);
185 onPacket: packet => {
186 // Ensure that any packets received from the server on the worker
187 // thread are forwarded to the client on the main thread, as if
188 // they had been sent by the server on the main thread.
189 connection.send(packet);
193 // Ensure that any packets received from the client on the main thread
194 // to actors on the worker thread are forwarded to the server on the
196 connection.setForwarding(forwardingPrefix, transport);
199 workerTargetForm: message.workerTargetForm,
204 dbg.addListener(listener);
208 exports.connectToWorker = connectToWorker;