Files
tubestation/devtools/server/connectors/frame-connector.js
Alexandre Poirot 015d569ad6 Bug 1928510 - [devtools] Remove now-unused WebExtensionTargetActor. r=devtools-reviewers,devtools-backward-compat-reviewers,nchevobbe
WebExtensionTargetActor.getTarget is being removed and removes most of the now-useless
codebase involving connectToFrame and message manager.

This allows to simplify a bit the ParentProcessTargetActor which required
some tweaks to be subclassed correctly.

We can also remove the `consoleAPIListenerOptions` which was specific to
this special target actor retrieving all document's console messages.
Now each individual target actor, for each document will handle the messages distinctly.

Note that we weren't using WebExtensionDescriptorFront.connect.

Differential Revision: https://phabricator.services.mozilla.com/D220541
2024-11-04 13:13:04 +00:00

165 lines
5.2 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var { dumpn } = DevToolsUtils;
loader.lazyRequireGetter(
this,
"DevToolsServer",
"resource://devtools/server/devtools-server.js",
true
);
loader.lazyRequireGetter(
this,
"ChildDebuggerTransport",
"resource://devtools/shared/transport/child-transport.js",
true
);
loader.lazyRequireGetter(
this,
"EventEmitter",
"resource://devtools/shared/event-emitter.js"
);
/**
* Start a DevTools server in a remote frame's process and add it as a child server for
* an active connection.
*
* @param object connection
* The devtools server connection to use.
* @param Element frame
* The frame element with remote content to connect to.
* @param function [onDestroy]
* Optional function to invoke when the child process closes or the connection
* shuts down. (Need to forget about the related target actor.)
* @return object
* A promise object that is resolved once the connection is established.
*/
function connectToFrame(connection, frame, onDestroy) {
return new Promise(resolve => {
// Get messageManager from XUL browser (which might be a specialized tunnel for RDM)
// or else fallback to asking the frameLoader itself.
const mm = frame.messageManager || frame.frameLoader.messageManager;
mm.loadFrameScript("resource://devtools/server/startup/frame.js", false);
const trackMessageManager = () => {
if (!actor) {
mm.addMessageListener("debug:actor", onActorCreated);
}
};
const untrackMessageManager = () => {
if (!actor) {
mm.removeMessageListener("debug:actor", onActorCreated);
}
};
let actor, childTransport;
const prefix = connection.allocID("child");
// Compute the same prefix that's used by DevToolsServerConnection
const connPrefix = prefix + "/";
const onActorCreated = DevToolsUtils.makeInfallible(function (msg) {
if (msg.json.prefix != prefix) {
return;
}
mm.removeMessageListener("debug:actor", onActorCreated);
// Pipe Debugger message from/to parent/child via the message manager
childTransport = new ChildDebuggerTransport(mm, prefix);
childTransport.hooks = {
// Pipe all the messages from content process actors back to the client
// through the parent process connection.
onPacket: connection.send.bind(connection),
};
childTransport.ready();
connection.setForwarding(prefix, childTransport);
dumpn(`Start forwarding for frame with prefix ${prefix}`);
actor = msg.json.actor;
resolve(actor);
});
const destroy = DevToolsUtils.makeInfallible(function () {
EventEmitter.off(connection, "closed", destroy);
Services.obs.removeObserver(
onMessageManagerClose,
"message-manager-close"
);
// TODO: Remove this deprecated path once it's no longer needed by add-ons.
DevToolsServer.emit("disconnected-from-child:" + connPrefix, {
mm,
prefix: connPrefix,
});
if (actor) {
actor = null;
}
// Notify the tab descriptor about the destruction before the call to
// `cancelForwarding`, so that we notify about the target destruction
// *before* we purge all request for this prefix.
// When we purge the requests, we also destroy all related fronts,
// including the target front. This clears all event listeners
// and ultimately prevent target-destroyed from firing.
if (onDestroy) {
onDestroy(mm);
}
if (childTransport) {
// If we have a child transport, the actor has already
// been created. We need to stop using this message manager.
childTransport.close();
childTransport = null;
connection.cancelForwarding(prefix);
// ... and notify the child process to clean the target-scoped actors.
try {
// Bug 1169643: Ignore any exception as the child process
// may already be destroyed by now.
mm.sendAsyncMessage("debug:disconnect", { prefix });
} catch (e) {
// Nothing to do
}
} else {
// Otherwise, the frame has been closed before the actor
// had a chance to be created, so we are not able to create
// the actor.
resolve(null);
}
// Cleanup all listeners
untrackMessageManager();
});
// Listen for various messages and frame events
trackMessageManager();
// Listen for app process exit
const onMessageManagerClose = function (subject) {
if (subject == mm) {
destroy();
}
};
Services.obs.addObserver(onMessageManagerClose, "message-manager-close");
// Listen for connection close to cleanup things
// when user unplug the device or we lose the connection somehow.
EventEmitter.on(connection, "closed", destroy);
mm.sendAsyncMessage("debug:connect", {
prefix,
});
});
}
exports.connectToFrame = connectToFrame;