summaryrefslogtreecommitdiffstats
path: root/devtools/client/aboutdebugging/src/middleware
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 /devtools/client/aboutdebugging/src/middleware
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 'devtools/client/aboutdebugging/src/middleware')
-rw-r--r--devtools/client/aboutdebugging/src/middleware/debug-target-listener.js62
-rw-r--r--devtools/client/aboutdebugging/src/middleware/error-logging.js35
-rw-r--r--devtools/client/aboutdebugging/src/middleware/event-recording.js270
-rw-r--r--devtools/client/aboutdebugging/src/middleware/extension-component-data.js80
-rw-r--r--devtools/client/aboutdebugging/src/middleware/moz.build13
-rw-r--r--devtools/client/aboutdebugging/src/middleware/process-component-data.js65
-rw-r--r--devtools/client/aboutdebugging/src/middleware/tab-component-data.js51
-rw-r--r--devtools/client/aboutdebugging/src/middleware/worker-component-data.js84
8 files changed, 660 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/src/middleware/debug-target-listener.js b/devtools/client/aboutdebugging/src/middleware/debug-target-listener.js
new file mode 100644
index 0000000000..ecd2d6d309
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/debug-target-listener.js
@@ -0,0 +1,62 @@
+/* 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 {
+ UNWATCH_RUNTIME_START,
+ WATCH_RUNTIME_SUCCESS,
+} = require("devtools/client/aboutdebugging/src/constants");
+const Actions = require("devtools/client/aboutdebugging/src/actions/index");
+
+function debugTargetListenerMiddleware(store) {
+ const onExtensionsUpdated = () => {
+ store.dispatch(Actions.requestExtensions());
+ };
+
+ const onTabsUpdated = () => {
+ store.dispatch(Actions.requestTabs());
+ };
+
+ const onWorkersUpdated = () => {
+ store.dispatch(Actions.requestWorkers());
+ };
+
+ return next => action => {
+ switch (action.type) {
+ case WATCH_RUNTIME_SUCCESS: {
+ const { runtime } = action;
+ const { clientWrapper } = runtime.runtimeDetails;
+
+ // Tabs
+ clientWrapper.on("tabListChanged", onTabsUpdated);
+
+ // Addons
+ clientWrapper.on("addonListChanged", onExtensionsUpdated);
+
+ // Workers
+ clientWrapper.on("workersUpdated", onWorkersUpdated);
+ break;
+ }
+ case UNWATCH_RUNTIME_START: {
+ const { runtime } = action;
+ const { clientWrapper } = runtime.runtimeDetails;
+
+ // Tabs
+ clientWrapper.off("tabListChanged", onTabsUpdated);
+
+ // Addons
+ clientWrapper.off("addonListChanged", onExtensionsUpdated);
+
+ // Workers
+ clientWrapper.off("workersUpdated", onWorkersUpdated);
+ break;
+ }
+ }
+
+ return next(action);
+ };
+}
+
+module.exports = debugTargetListenerMiddleware;
diff --git a/devtools/client/aboutdebugging/src/middleware/error-logging.js b/devtools/client/aboutdebugging/src/middleware/error-logging.js
new file mode 100644
index 0000000000..fd04f34b76
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/error-logging.js
@@ -0,0 +1,35 @@
+/* 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";
+
+/**
+ * Error logging middleware that will forward all actions that contain an error property
+ * to the console.
+ */
+function errorLoggingMiddleware() {
+ return next => action => {
+ if (action.error) {
+ const { error } = action;
+ if (error.message) {
+ console.error(`[ACTION FAILED] ${action.type}: ${error.message}`);
+ } else if (typeof error === "string") {
+ // All failure actions should dispatch an error object instead of a message.
+ // We allow some flexibility to still provide some error logging.
+ console.error(`[ACTION FAILED] ${action.type}: ${error}`);
+ console.error(
+ `[ACTION FAILED] ${action.type} should dispatch the error object!`
+ );
+ }
+
+ if (error.stack) {
+ console.error(error.stack);
+ }
+ }
+
+ return next(action);
+ };
+}
+
+module.exports = errorLoggingMiddleware;
diff --git a/devtools/client/aboutdebugging/src/middleware/event-recording.js b/devtools/client/aboutdebugging/src/middleware/event-recording.js
new file mode 100644
index 0000000000..0070fc0d7d
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/event-recording.js
@@ -0,0 +1,270 @@
+/* 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 Telemetry = require("devtools/client/shared/telemetry");
+loader.lazyGetter(this, "telemetry", () => new Telemetry());
+// This is a unique id that should be submitted with all about:debugging events.
+loader.lazyGetter(this, "sessionId", () =>
+ parseInt(telemetry.msSinceProcessStart(), 10)
+);
+
+const {
+ CONNECT_RUNTIME_CANCEL,
+ CONNECT_RUNTIME_FAILURE,
+ CONNECT_RUNTIME_NOT_RESPONDING,
+ CONNECT_RUNTIME_START,
+ CONNECT_RUNTIME_SUCCESS,
+ DISCONNECT_RUNTIME_SUCCESS,
+ REMOTE_RUNTIMES_UPDATED,
+ RUNTIMES,
+ SELECT_PAGE_SUCCESS,
+ SHOW_PROFILER_DIALOG,
+ TELEMETRY_RECORD,
+ UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS,
+} = require("devtools/client/aboutdebugging/src/constants");
+
+const {
+ findRuntimeById,
+ getAllRuntimes,
+ getCurrentRuntime,
+} = require("devtools/client/aboutdebugging/src/modules/runtimes-state-helper");
+
+function recordEvent(method, details) {
+ // Add the session id to the event details.
+ const eventDetails = Object.assign({}, details, { session_id: sessionId });
+ telemetry.recordEvent(method, "aboutdebugging", null, eventDetails);
+
+ // For close and open events, also ping the regular telemetry helpers used
+ // for all DevTools UIs.
+ if (method === "open_adbg") {
+ telemetry.toolOpened("aboutdebugging", sessionId, window.AboutDebugging);
+ } else if (method === "close_adbg") {
+ // XXX: Note that aboutdebugging has no histogram created for
+ // TIME_ACTIVE_SECOND, so calling toolClosed will not actually
+ // record anything.
+ telemetry.toolClosed("aboutdebugging", sessionId, window.AboutDebugging);
+ }
+}
+
+const telemetryRuntimeIds = new Map();
+// Create an anonymous id that will allow to track all events related to a runtime without
+// leaking personal data related to this runtime.
+function getTelemetryRuntimeId(id) {
+ if (!telemetryRuntimeIds.has(id)) {
+ const randomId = (Math.random() * 100000) | 0;
+ telemetryRuntimeIds.set(id, "runtime-" + randomId);
+ }
+ return telemetryRuntimeIds.get(id);
+}
+
+function getCurrentRuntimeIdForTelemetry(store) {
+ const id = getCurrentRuntime(store.getState().runtimes).id;
+ return getTelemetryRuntimeId(id);
+}
+
+function getRuntimeEventExtras(runtime) {
+ const { extra, runtimeDetails } = runtime;
+
+ // deviceName can be undefined for non-usb devices, but we should not log "undefined".
+ const deviceName = extra?.deviceName || "";
+ const runtimeShortName = runtime.type === RUNTIMES.USB ? runtime.name : "";
+ const runtimeName = runtimeDetails?.info.name || "";
+ return {
+ connection_type: runtime.type,
+ device_name: deviceName,
+ runtime_id: getTelemetryRuntimeId(runtime.id),
+ runtime_name: runtimeName || runtimeShortName,
+ };
+}
+
+function onConnectRuntimeSuccess(action, store) {
+ if (action.runtime.type === RUNTIMES.THIS_FIREFOX) {
+ // Only record connection and disconnection events for remote runtimes.
+ return;
+ }
+ // When we just connected to a runtime, the runtimeDetails are not in the store yet,
+ // so we merge it here to retrieve the expected telemetry data.
+ const storeRuntime = findRuntimeById(
+ action.runtime.id,
+ store.getState().runtimes
+ );
+ const runtime = Object.assign({}, storeRuntime, {
+ runtimeDetails: action.runtime.runtimeDetails,
+ });
+ const extras = Object.assign({}, getRuntimeEventExtras(runtime), {
+ runtime_os: action.runtime.runtimeDetails.info.os,
+ runtime_version: action.runtime.runtimeDetails.info.version,
+ });
+ recordEvent("runtime_connected", extras);
+}
+
+function onDisconnectRuntimeSuccess(action, store) {
+ const runtime = findRuntimeById(action.runtime.id, store.getState().runtimes);
+ if (runtime.type === RUNTIMES.THIS_FIREFOX) {
+ // Only record connection and disconnection events for remote runtimes.
+ return;
+ }
+
+ recordEvent("runtime_disconnected", getRuntimeEventExtras(runtime));
+}
+
+function onRemoteRuntimesUpdated(action, store) {
+ // Compare new runtimes with the existing runtimes to detect if runtimes, devices
+ // have been added or removed.
+ const newRuntimes = action.runtimes;
+ const allRuntimes = getAllRuntimes(store.getState().runtimes);
+ const oldRuntimes = allRuntimes.filter(r => r.type === action.runtimeType);
+
+ // Check if all the old runtimes and devices are still available in the updated
+ // array.
+ for (const oldRuntime of oldRuntimes) {
+ const runtimeRemoved = newRuntimes.every(r => r.id !== oldRuntime.id);
+ if (runtimeRemoved && !oldRuntime.isUnplugged) {
+ recordEvent("runtime_removed", getRuntimeEventExtras(oldRuntime));
+ }
+ }
+
+ // Using device names as unique IDs is inaccurate. See Bug 1544582.
+ const oldDeviceNames = new Set(oldRuntimes.map(r => r.extra.deviceName));
+ for (const oldDeviceName of oldDeviceNames) {
+ const newRuntime = newRuntimes.find(
+ r => r.extra.deviceName === oldDeviceName
+ );
+ const oldRuntime = oldRuntimes.find(
+ r => r.extra.deviceName === oldDeviceName
+ );
+ const isUnplugged = newRuntime?.isUnplugged && !oldRuntime.isUnplugged;
+ if (oldDeviceName && (!newRuntime || isUnplugged)) {
+ recordEvent("device_removed", {
+ connection_type: action.runtimeType,
+ device_name: oldDeviceName,
+ });
+ }
+ }
+
+ // Check if the new runtimes and devices were already available in the existing
+ // array.
+ for (const newRuntime of newRuntimes) {
+ const runtimeAdded = oldRuntimes.every(r => r.id !== newRuntime.id);
+ if (runtimeAdded && !newRuntime.isUnplugged) {
+ recordEvent("runtime_added", getRuntimeEventExtras(newRuntime));
+ }
+ }
+
+ // Using device names as unique IDs is inaccurate. See Bug 1544582.
+ const newDeviceNames = new Set(newRuntimes.map(r => r.extra.deviceName));
+ for (const newDeviceName of newDeviceNames) {
+ const newRuntime = newRuntimes.find(
+ r => r.extra.deviceName === newDeviceName
+ );
+ const oldRuntime = oldRuntimes.find(
+ r => r.extra.deviceName === newDeviceName
+ );
+ const isPlugged = oldRuntime?.isUnplugged && !newRuntime.isUnplugged;
+
+ if (newDeviceName && (!oldRuntime || isPlugged)) {
+ recordEvent("device_added", {
+ connection_type: action.runtimeType,
+ device_name: newDeviceName,
+ });
+ }
+ }
+}
+
+function recordConnectionAttempt(connectionId, runtimeId, status, store) {
+ const runtime = findRuntimeById(runtimeId, store.getState().runtimes);
+ if (runtime.type === RUNTIMES.THIS_FIREFOX) {
+ // Only record connection_attempt events for remote runtimes.
+ return;
+ }
+
+ recordEvent("connection_attempt", {
+ connection_id: connectionId,
+ connection_type: runtime.type,
+ runtime_id: getTelemetryRuntimeId(runtimeId),
+ status: status,
+ });
+}
+
+/**
+ * This middleware will record events to telemetry for some specific actions.
+ */
+function eventRecordingMiddleware(store) {
+ return next => action => {
+ switch (action.type) {
+ case CONNECT_RUNTIME_CANCEL:
+ recordConnectionAttempt(
+ action.connectionId,
+ action.id,
+ "cancelled",
+ store
+ );
+ break;
+ case CONNECT_RUNTIME_FAILURE:
+ recordConnectionAttempt(
+ action.connectionId,
+ action.id,
+ "failed",
+ store
+ );
+ break;
+ case CONNECT_RUNTIME_NOT_RESPONDING:
+ recordConnectionAttempt(
+ action.connectionId,
+ action.id,
+ "not responding",
+ store
+ );
+ break;
+ case CONNECT_RUNTIME_START:
+ recordConnectionAttempt(action.connectionId, action.id, "start", store);
+ break;
+ case CONNECT_RUNTIME_SUCCESS:
+ recordConnectionAttempt(
+ action.connectionId,
+ action.runtime.id,
+ "success",
+ store
+ );
+ onConnectRuntimeSuccess(action, store);
+ break;
+ case DISCONNECT_RUNTIME_SUCCESS:
+ onDisconnectRuntimeSuccess(action, store);
+ break;
+ case REMOTE_RUNTIMES_UPDATED:
+ onRemoteRuntimesUpdated(action, store);
+ break;
+ case SELECT_PAGE_SUCCESS:
+ recordEvent("select_page", { page_type: action.page });
+ break;
+ case SHOW_PROFILER_DIALOG:
+ recordEvent("show_profiler", {
+ runtime_id: getCurrentRuntimeIdForTelemetry(store),
+ });
+ break;
+ case TELEMETRY_RECORD:
+ const { method, details } = action;
+ if (method) {
+ recordEvent(method, details);
+ } else {
+ console.error(
+ `[RECORD EVENT FAILED] ${action.type}: no "method" property`
+ );
+ }
+ break;
+ case UPDATE_CONNECTION_PROMPT_SETTING_SUCCESS:
+ recordEvent("update_conn_prompt", {
+ prompt_enabled: `${action.connectionPromptEnabled}`,
+ runtime_id: getCurrentRuntimeIdForTelemetry(store),
+ });
+ break;
+ }
+
+ return next(action);
+ };
+}
+
+module.exports = eventRecordingMiddleware;
diff --git a/devtools/client/aboutdebugging/src/middleware/extension-component-data.js b/devtools/client/aboutdebugging/src/middleware/extension-component-data.js
new file mode 100644
index 0000000000..33f3121230
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/extension-component-data.js
@@ -0,0 +1,80 @@
+/* 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 {
+ DEBUG_TARGETS,
+ REQUEST_EXTENSIONS_SUCCESS,
+} = require("devtools/client/aboutdebugging/src/constants");
+
+const {
+ getExtensionUuid,
+ parseFileUri,
+} = require("devtools/client/aboutdebugging/src/modules/extensions-helper");
+
+/**
+ * This middleware converts extensions object that get from DevToolsClient.listAddons()
+ * to data which is used in DebugTargetItem.
+ */
+const extensionComponentDataMiddleware = store => next => action => {
+ switch (action.type) {
+ case REQUEST_EXTENSIONS_SUCCESS: {
+ action.installedExtensions = toComponentData(action.installedExtensions);
+ action.temporaryExtensions = toComponentData(action.temporaryExtensions);
+ break;
+ }
+ }
+
+ return next(action);
+};
+
+function getFilePath(extension) {
+ // Only show file system paths, and only for temporarily installed add-ons.
+ if (
+ !extension.temporarilyInstalled ||
+ !extension.url ||
+ !extension.url.startsWith("file://")
+ ) {
+ return null;
+ }
+
+ return parseFileUri(extension.url);
+}
+
+function toComponentData(extensions) {
+ return extensions.map(extension => {
+ const type = DEBUG_TARGETS.EXTENSION;
+ const {
+ actor,
+ iconDataURL,
+ iconURL,
+ id,
+ manifestURL,
+ name,
+ warnings,
+ } = extension;
+ const icon =
+ iconDataURL ||
+ iconURL ||
+ "chrome://mozapps/skin/extensions/extensionGeneric.svg";
+ const location = getFilePath(extension);
+ const uuid = getExtensionUuid(extension);
+ return {
+ name,
+ icon,
+ id,
+ type,
+ details: {
+ actor,
+ location,
+ manifestURL,
+ uuid,
+ warnings: warnings || [],
+ },
+ };
+ });
+}
+
+module.exports = extensionComponentDataMiddleware;
diff --git a/devtools/client/aboutdebugging/src/middleware/moz.build b/devtools/client/aboutdebugging/src/middleware/moz.build
new file mode 100644
index 0000000000..f50150f569
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/moz.build
@@ -0,0 +1,13 @@
+# 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/.
+
+DevToolsModules(
+ "debug-target-listener.js",
+ "error-logging.js",
+ "event-recording.js",
+ "extension-component-data.js",
+ "process-component-data.js",
+ "tab-component-data.js",
+ "worker-component-data.js",
+)
diff --git a/devtools/client/aboutdebugging/src/middleware/process-component-data.js b/devtools/client/aboutdebugging/src/middleware/process-component-data.js
new file mode 100644
index 0000000000..72c9f67d8c
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/process-component-data.js
@@ -0,0 +1,65 @@
+/* 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 Services = require("Services");
+const { l10n } = require("devtools/client/aboutdebugging/src/modules/l10n");
+
+const {
+ DEBUG_TARGETS,
+ PREFERENCES,
+ REQUEST_PROCESSES_SUCCESS,
+} = require("devtools/client/aboutdebugging/src/constants");
+
+/**
+ * This middleware converts tabs object that get from DevToolsClient.listProcesses() to
+ * data which is used in DebugTargetItem.
+ */
+const processComponentDataMiddleware = store => next => action => {
+ switch (action.type) {
+ case REQUEST_PROCESSES_SUCCESS: {
+ const mainProcessComponentData = toMainProcessComponentData(
+ action.mainProcess
+ );
+ action.processes = [mainProcessComponentData];
+ break;
+ }
+ }
+
+ return next(action);
+};
+
+function toMainProcessComponentData(process) {
+ const type = DEBUG_TARGETS.PROCESS;
+ const id = process.id;
+ const icon = "chrome://devtools/skin/images/aboutdebugging-process-icon.svg";
+
+ const isMultiProcessToolboxEnabled = Services.prefs.getBoolPref(
+ PREFERENCES.FISSION_BROWSER_TOOLBOX,
+ false
+ );
+
+ // For now, we assume there is only one process and this is the main process
+ // So the name and title are for a remote (multiprocess) browser toolbox.
+ const name = isMultiProcessToolboxEnabled
+ ? l10n.getString("about-debugging-multiprocess-toolbox-name")
+ : l10n.getString("about-debugging-main-process-name");
+
+ const description = isMultiProcessToolboxEnabled
+ ? l10n.getString("about-debugging-multiprocess-toolbox-description")
+ : l10n.getString("about-debugging-main-process-description2");
+
+ return {
+ name,
+ icon,
+ id,
+ type,
+ details: {
+ description,
+ },
+ };
+}
+
+module.exports = processComponentDataMiddleware;
diff --git a/devtools/client/aboutdebugging/src/middleware/tab-component-data.js b/devtools/client/aboutdebugging/src/middleware/tab-component-data.js
new file mode 100644
index 0000000000..fe9966f8cb
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/tab-component-data.js
@@ -0,0 +1,51 @@
+/* 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 {
+ DEBUG_TARGETS,
+ REQUEST_TABS_SUCCESS,
+} = require("devtools/client/aboutdebugging/src/constants");
+
+/**
+ * This middleware converts tabs object that get from DevToolsClient.listTabs() to data
+ * which is used in DebugTargetItem.
+ */
+const tabComponentDataMiddleware = store => next => action => {
+ switch (action.type) {
+ case REQUEST_TABS_SUCCESS: {
+ action.tabs = toComponentData(action.tabs);
+ break;
+ }
+ }
+
+ return next(action);
+};
+
+function toComponentData(tabs) {
+ return tabs.map(tab => {
+ const type = DEBUG_TARGETS.TAB;
+ const id = tab.outerWindowID;
+ const icon = tab.favicon
+ ? `data:image/png;base64,${btoa(
+ String.fromCharCode.apply(String, tab.favicon)
+ )}`
+ : "chrome://devtools/skin/images/globe.svg";
+ const name = tab.title || tab.url;
+ const { url, isZombieTab } = tab;
+ return {
+ name,
+ icon,
+ id,
+ type,
+ details: {
+ isZombieTab,
+ url,
+ },
+ };
+ });
+}
+
+module.exports = tabComponentDataMiddleware;
diff --git a/devtools/client/aboutdebugging/src/middleware/worker-component-data.js b/devtools/client/aboutdebugging/src/middleware/worker-component-data.js
new file mode 100644
index 0000000000..8507c50160
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/middleware/worker-component-data.js
@@ -0,0 +1,84 @@
+/* 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 { Ci } = require("chrome");
+
+const {
+ DEBUG_TARGETS,
+ REQUEST_WORKERS_SUCCESS,
+ SERVICE_WORKER_FETCH_STATES,
+ SERVICE_WORKER_STATUSES,
+} = require("devtools/client/aboutdebugging/src/constants");
+
+/**
+ * This middleware converts workers object that get from DevToolsClient.listAllWorkers()
+ * to data which is used in DebugTargetItem.
+ */
+const workerComponentDataMiddleware = store => next => action => {
+ switch (action.type) {
+ case REQUEST_WORKERS_SUCCESS: {
+ action.otherWorkers = toComponentData(action.otherWorkers);
+ action.serviceWorkers = toComponentData(action.serviceWorkers, true);
+ action.sharedWorkers = toComponentData(action.sharedWorkers);
+ break;
+ }
+ }
+
+ return next(action);
+};
+
+function getServiceWorkerStatus(worker) {
+ const isActive = worker.state === Ci.nsIServiceWorkerInfo.STATE_ACTIVATED;
+ const isRunning = !!worker.workerDescriptorFront;
+
+ if (isActive && isRunning) {
+ return SERVICE_WORKER_STATUSES.RUNNING;
+ } else if (isActive) {
+ return SERVICE_WORKER_STATUSES.STOPPED;
+ }
+
+ // We cannot get service worker registrations unless the registration is in
+ // ACTIVE state. Unable to know the actual state ("installing", "waiting"), we
+ // display a custom state "registering" for now. See Bug 1153292.
+ return SERVICE_WORKER_STATUSES.REGISTERING;
+}
+
+function toComponentData(workers, isServiceWorker) {
+ return workers.map(worker => {
+ // Here `worker` is the worker object created by RootFront.listAllWorkers
+ const type = DEBUG_TARGETS.WORKER;
+ const icon = "chrome://devtools/skin/images/debugging-workers.svg";
+ let { fetch } = worker;
+ const { id, name, registrationFront, scope, subscription } = worker;
+
+ let pushServiceEndpoint = null;
+ let status = null;
+
+ if (isServiceWorker) {
+ fetch = fetch
+ ? SERVICE_WORKER_FETCH_STATES.LISTENING
+ : SERVICE_WORKER_FETCH_STATES.NOT_LISTENING;
+ status = getServiceWorkerStatus(worker);
+ pushServiceEndpoint = subscription ? subscription.endpoint : null;
+ }
+
+ return {
+ details: {
+ fetch,
+ pushServiceEndpoint,
+ registrationFront,
+ scope,
+ status,
+ },
+ icon,
+ id,
+ name,
+ type,
+ };
+ });
+}
+
+module.exports = workerComponentDataMiddleware;