commit 4aafd5370851211ca68948717799a3b0c8037614
parent 7fcfc7eec91dd48ccc484c3bf49337e5e8608e82
Author: Hubert Boma Manilla <hmanilla@mozilla.com>
Date: Fri, 19 Dec 2025 17:14:37 +0000
Bug 1960549 - [devtools] Add resource watcher for webtransport events r=devtools-reviewers,nchevobbe
This adds the resource watcher for webtransport events.
Differential Revision: https://phabricator.services.mozilla.com/D259239
Diffstat:
4 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/devtools/server/actors/resources/moz.build b/devtools/server/actors/resources/moz.build
@@ -38,6 +38,7 @@ DevToolsModules(
"stylesheets.js",
"thread-states.js",
"websockets.js",
+ "webtransport.js",
)
with Files("*-messages.js"):
diff --git a/devtools/server/actors/resources/webtransport.js b/devtools/server/actors/resources/webtransport.js
@@ -0,0 +1,79 @@
+/* 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";
+
+const webTransportEventService = Cc[
+ "@mozilla.org/webtransportevent/service;1"
+].getService(Ci.nsIWebTransportEventService);
+
+class WebTransportWatcher {
+ constructor() {
+ this.windowIds = new Set();
+ this.abortController = new AbortController();
+ this.onWindowReady = this.onWindowReady.bind(this);
+ this.onWindowDestroy = this.onWindowDestroy.bind(this);
+ }
+
+ watch(targetActor, { onAvailable }) {
+ this.targetActor = targetActor;
+ this.onAvailable = onAvailable;
+
+ for (const window of this.targetActor.windows) {
+ const { innerWindowId } = window.windowGlobalChild;
+ this.startListening(innerWindowId);
+ }
+
+ // On navigate/reload we should re-start listening with the new `innerWindowID`
+ if (!this.targetActor.followWindowGlobalLifeCycle) {
+ this.targetActor.on("window-ready", this.onWindowReady, {
+ signal: this.abortController.signal,
+ });
+ this.targetActor.on("window-destroyed", this.onWindowDestroy, {
+ signal: this.abortController.signal,
+ });
+ }
+ }
+
+ onWindowReady({ window }) {
+ const { innerWindowId } = window.windowGlobalChild;
+ this.startListening(innerWindowId);
+ }
+
+ onWindowDestroy({ id }) {
+ this.stopListening(id);
+ }
+
+ startListening(innerWindowId) {
+ if (!this.windowIds.has(innerWindowId)) {
+ this.windowIds.add(innerWindowId);
+ webTransportEventService.addListener(innerWindowId, this);
+ }
+ }
+
+ stopListening(innerWindowId) {
+ if (this.windowIds.has(innerWindowId)) {
+ this.windowIds.delete(innerWindowId);
+ if (!webTransportEventService.hasListenerFor(innerWindowId)) {
+ // The listener might have already been cleaned up on `window-destroy`.
+ console.warn(
+ "Already stopped listening to webtransport events for this window."
+ );
+ return;
+ }
+ webTransportEventService.removeListener(innerWindowId, this);
+ }
+ }
+
+ destroy() {
+ this.abortController.abort();
+ for (const id of this.windowIds) {
+ this.stopListening(id);
+ }
+ }
+
+ // TODO: methods for the webTransportEventService
+}
+
+module.exports = WebTransportWatcher;
diff --git a/devtools/server/tests/chrome/chrome.toml b/devtools/server/tests/chrome/chrome.toml
@@ -147,3 +147,5 @@ support-files = [
["test_unsafeDereference.html"]
["test_webconsole-node-grip.html"]
+
+["test_webtransport-listeners.html"]
diff --git a/devtools/server/tests/chrome/test_webtransport-listeners.html b/devtools/server/tests/chrome/test_webtransport-listeners.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test the WebTransport watcher </title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+ 'use strict';
+ const { require } = ChromeUtils.importESModule("resource://devtools/shared/loader/Loader.sys.mjs");
+ const WebTransportWatcher = require("devtools/server/actors/resources/webtransport.js");
+ var service = Cc["@mozilla.org/webtransportevent/service;1"]
+ .getService(Ci.nsIWebTransportEventService);
+ ok(!!service, "We have the nsIWebTransportEventService");
+
+ var innerWindowId = window.windowGlobalChild.innerWindowId;
+ ok(innerWindowId, "We have a valid innerWindowID: " + innerWindowId);
+
+ const watcher = new WebTransportWatcher();
+
+ watcher.startListening(innerWindowId);
+ ok(service.hasListenerFor(innerWindowId), "Service has listener for the window");
+
+ watcher.stopListening(innerWindowId);
+ ok(!service.hasListenerFor(innerWindowId), "Service no longer has a listener for the window");
+
+ // Make sure this does not throw if the listener does not exist.
+ watcher.stopListening(innerWindowId);
+</script>
+</body>
+</html>