summaryrefslogtreecommitdiffstats
path: root/remote/targets/TargetList.jsm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /remote/targets/TargetList.jsm
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--remote/targets/TargetList.jsm173
1 files changed, 173 insertions, 0 deletions
diff --git a/remote/targets/TargetList.jsm b/remote/targets/TargetList.jsm
new file mode 100644
index 0000000000..7117fbbee4
--- /dev/null
+++ b/remote/targets/TargetList.jsm
@@ -0,0 +1,173 @@
+/* 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 EXPORTED_SYMBOLS = ["TargetList"];
+
+const { EventEmitter } = ChromeUtils.import(
+ "resource://gre/modules/EventEmitter.jsm"
+);
+const { TabTarget } = ChromeUtils.import(
+ "chrome://remote/content/targets/TabTarget.jsm"
+);
+const { MainProcessTarget } = ChromeUtils.import(
+ "chrome://remote/content/targets/MainProcessTarget.jsm"
+);
+const { TabObserver } = ChromeUtils.import(
+ "chrome://remote/content/observers/TargetObserver.jsm"
+);
+
+class TargetList {
+ constructor() {
+ // Target ID -> Target
+ this._targets = new Map();
+
+ EventEmitter.decorate(this);
+ }
+
+ /**
+ * Start listing and listening for all the debuggable targets
+ */
+ async watchForTargets() {
+ await this.watchForTabs();
+ }
+
+ unwatchForTargets() {
+ this.unwatchForTabs();
+ }
+
+ /**
+ * Watch for all existing and new tabs being opened.
+ * So that we can create the related TabTarget instance for
+ * each of them.
+ */
+ async watchForTabs() {
+ if (this.tabObserver) {
+ throw new Error("Targets is already watching for new tabs");
+ }
+ this.tabObserver = new TabObserver({ registerExisting: true });
+ this.tabObserver.on("open", async (eventName, tab) => {
+ const target = new TabTarget(this, tab.linkedBrowser);
+ this.registerTarget(target);
+ });
+ this.tabObserver.on("close", (eventName, tab) => {
+ const browser = tab.linkedBrowser;
+ // Ignore the browsers that haven't had time to initialize.
+ if (!browser.browsingContext) {
+ return;
+ }
+ const target = this.getByBrowsingContext(browser.browsingContext.id);
+ if (target) {
+ this.destroyTarget(target);
+ }
+ });
+ await this.tabObserver.start();
+ }
+
+ unwatchForTabs() {
+ if (this.tabObserver) {
+ this.tabObserver.stop();
+ this.tabObserver = null;
+ }
+ }
+
+ /**
+ * To be called right after instantiating a new Target instance.
+ * This will hold the new instance in the list and notify about
+ * its creation.
+ */
+ registerTarget(target) {
+ this._targets.set(target.id, target);
+ this.emit("target-created", target);
+ }
+
+ /**
+ * To be called when the debuggable target has been destroy.
+ * So that we can notify it no longer exists and disconnect
+ * all connecting made to debug it.
+ */
+ destroyTarget(target) {
+ target.destructor();
+ this._targets.delete(target.id);
+ this.emit("target-destroyed", target);
+ }
+
+ /**
+ * Destroy all the registered target of all kinds.
+ * This will end up dropping all connections made to debug any of them.
+ */
+ destructor() {
+ for (const target of this) {
+ this.destroyTarget(target);
+ }
+ this._targets.clear();
+ if (this.mainProcessTarget) {
+ this.mainProcessTarget = null;
+ }
+
+ this.unwatchForTargets();
+ }
+
+ get size() {
+ return this._targets.size;
+ }
+
+ /**
+ * Get Target instance by target id
+ *
+ * @param {string} id
+ * Target id
+ *
+ * @return {Target}
+ */
+ getById(id) {
+ return this._targets.get(id);
+ }
+
+ /**
+ * Get Target instance by browsing context id
+ *
+ * @param {number} id
+ * browsing context id
+ *
+ * @return {Target}
+ */
+ getByBrowsingContext(id) {
+ let rv;
+ for (const target of this._targets.values()) {
+ if (target.browsingContext && target.browsingContext.id === id) {
+ rv = target;
+ break;
+ }
+ }
+ return rv;
+ }
+
+ /**
+ * Get the Target instance for the main process.
+ * This target is a singleton and only exposes a subset of domains.
+ */
+ getMainProcessTarget() {
+ if (!this.mainProcessTarget) {
+ this.mainProcessTarget = new MainProcessTarget(this);
+ this.registerTarget(this.mainProcessTarget);
+ }
+ return this.mainProcessTarget;
+ }
+
+ *[Symbol.iterator]() {
+ for (const target of this._targets.values()) {
+ yield target;
+ }
+ }
+
+ toJSON() {
+ return [...this];
+ }
+
+ toString() {
+ return `[object TargetList ${this.size}]`;
+ }
+}