summaryrefslogtreecommitdiffstats
path: root/devtools/client/aboutdebugging/src/actions/debug-targets.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/aboutdebugging/src/actions/debug-targets.js')
-rw-r--r--devtools/client/aboutdebugging/src/actions/debug-targets.js356
1 files changed, 356 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/src/actions/debug-targets.js b/devtools/client/aboutdebugging/src/actions/debug-targets.js
new file mode 100644
index 0000000000..33b2f1cbea
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/actions/debug-targets.js
@@ -0,0 +1,356 @@
+/* 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 { AddonManager } = ChromeUtils.importESModule(
+ "resource://gre/modules/AddonManager.sys.mjs",
+ // AddonManager is a singleton, never create two instances of it.
+ { loadInDevToolsLoader: false }
+);
+const {
+ remoteClientManager,
+} = require("resource://devtools/client/shared/remote-debugging/remote-client-manager.js");
+
+const {
+ l10n,
+} = require("resource://devtools/client/aboutdebugging/src/modules/l10n.js");
+
+const {
+ isSupportedDebugTargetPane,
+} = require("resource://devtools/client/aboutdebugging/src/modules/debug-target-support.js");
+
+const {
+ openTemporaryExtension,
+} = require("resource://devtools/client/aboutdebugging/src/modules/extensions-helper.js");
+
+const {
+ getCurrentClient,
+ getCurrentRuntime,
+} = require("resource://devtools/client/aboutdebugging/src/modules/runtimes-state-helper.js");
+
+const {
+ gDevTools,
+} = require("resource://devtools/client/framework/devtools.js");
+
+const {
+ DEBUG_TARGETS,
+ DEBUG_TARGET_PANE,
+ REQUEST_EXTENSIONS_FAILURE,
+ REQUEST_EXTENSIONS_START,
+ REQUEST_EXTENSIONS_SUCCESS,
+ REQUEST_PROCESSES_FAILURE,
+ REQUEST_PROCESSES_START,
+ REQUEST_PROCESSES_SUCCESS,
+ REQUEST_TABS_FAILURE,
+ REQUEST_TABS_START,
+ REQUEST_TABS_SUCCESS,
+ REQUEST_WORKERS_FAILURE,
+ REQUEST_WORKERS_START,
+ REQUEST_WORKERS_SUCCESS,
+ TEMPORARY_EXTENSION_INSTALL_FAILURE,
+ TEMPORARY_EXTENSION_INSTALL_START,
+ TEMPORARY_EXTENSION_INSTALL_SUCCESS,
+ TEMPORARY_EXTENSION_RELOAD_FAILURE,
+ TEMPORARY_EXTENSION_RELOAD_START,
+ TEMPORARY_EXTENSION_RELOAD_SUCCESS,
+ TERMINATE_EXTENSION_BGSCRIPT_FAILURE,
+ TERMINATE_EXTENSION_BGSCRIPT_SUCCESS,
+ TERMINATE_EXTENSION_BGSCRIPT_START,
+ RUNTIMES,
+} = require("resource://devtools/client/aboutdebugging/src/constants.js");
+
+const Actions = require("resource://devtools/client/aboutdebugging/src/actions/index.js");
+
+function getTabForUrl(url) {
+ for (const navigator of Services.wm.getEnumerator("navigator:browser")) {
+ for (const browser of navigator.gBrowser.browsers) {
+ if (
+ browser.contentWindow &&
+ browser.contentWindow.location.href === url
+ ) {
+ return navigator.gBrowser.getTabForBrowser(browser);
+ }
+ }
+ }
+
+ return null;
+}
+
+function inspectDebugTarget(type, id) {
+ return async ({ dispatch, getState }) => {
+ const runtime = getCurrentRuntime(getState().runtimes);
+
+ if (
+ type == DEBUG_TARGETS.EXTENSION &&
+ runtime.id === RUNTIMES.THIS_FIREFOX
+ ) {
+ // Bug 1780912: To avoid UX issues when debugging local web extensions,
+ // we are opening the toolbox in an independant window.
+ // Whereas all others are opened in new tabs.
+ gDevTools.showToolboxForWebExtension(id);
+ } else {
+ const urlParams = {
+ type,
+ };
+ // Main process may not provide any ID.
+ if (id) {
+ urlParams.id = id;
+ }
+
+ if (runtime.id !== RUNTIMES.THIS_FIREFOX) {
+ urlParams.remoteId = remoteClientManager.getRemoteId(
+ runtime.id,
+ runtime.type
+ );
+ }
+
+ const url = `about:devtools-toolbox?${new window.URLSearchParams(
+ urlParams
+ )}`;
+
+ const existingTab = getTabForUrl(url);
+ if (existingTab) {
+ const navigator = existingTab.ownerGlobal;
+ navigator.gBrowser.selectedTab = existingTab;
+ navigator.focus();
+ } else {
+ window.open(url);
+ }
+ }
+
+ dispatch(
+ Actions.recordTelemetryEvent("inspect", {
+ target_type: type.toUpperCase(),
+ runtime_type: runtime.type,
+ })
+ );
+ };
+}
+
+function installTemporaryExtension() {
+ const message = l10n.getString(
+ "about-debugging-tmp-extension-install-message"
+ );
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: TEMPORARY_EXTENSION_INSTALL_START });
+ const file = await openTemporaryExtension(window, message);
+ try {
+ await AddonManager.installTemporaryAddon(file);
+ dispatch({ type: TEMPORARY_EXTENSION_INSTALL_SUCCESS });
+ } catch (e) {
+ dispatch({ type: TEMPORARY_EXTENSION_INSTALL_FAILURE, error: e });
+ }
+ };
+}
+
+function pushServiceWorker(id, registrationFront) {
+ return async ({ dispatch, getState }) => {
+ try {
+ // The push button is only available if canDebugServiceWorkers is true.
+ // With this configuration, `push` should always be called on the
+ // registration front, and not on the (service) WorkerTargetActor.
+ await registrationFront.push();
+ } catch (e) {
+ console.error(e);
+ }
+ };
+}
+
+function reloadTemporaryExtension(id) {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: TEMPORARY_EXTENSION_RELOAD_START, id });
+ const clientWrapper = getCurrentClient(getState().runtimes);
+
+ try {
+ const addonTargetFront = await clientWrapper.getAddon({ id });
+ await addonTargetFront.reload();
+ dispatch({ type: TEMPORARY_EXTENSION_RELOAD_SUCCESS, id });
+ } catch (e) {
+ const error = typeof e === "string" ? new Error(e) : e;
+ dispatch({ type: TEMPORARY_EXTENSION_RELOAD_FAILURE, id, error });
+ }
+ };
+}
+
+function removeTemporaryExtension(id) {
+ return async ({ getState }) => {
+ const clientWrapper = getCurrentClient(getState().runtimes);
+
+ try {
+ await clientWrapper.uninstallAddon({ id });
+ } catch (e) {
+ console.error(e);
+ }
+ };
+}
+
+function terminateExtensionBackgroundScript(id) {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: TERMINATE_EXTENSION_BGSCRIPT_START, id });
+ const clientWrapper = getCurrentClient(getState().runtimes);
+
+ try {
+ const addonTargetFront = await clientWrapper.getAddon({ id });
+ await addonTargetFront.terminateBackgroundScript();
+ dispatch({ type: TERMINATE_EXTENSION_BGSCRIPT_SUCCESS, id });
+ } catch (e) {
+ const error = typeof e === "string" ? new Error(e) : e;
+ dispatch({ type: TERMINATE_EXTENSION_BGSCRIPT_FAILURE, id, error });
+ }
+ };
+}
+
+function requestTabs() {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: REQUEST_TABS_START });
+
+ const runtime = getCurrentRuntime(getState().runtimes);
+ const clientWrapper = getCurrentClient(getState().runtimes);
+
+ try {
+ const isSupported = isSupportedDebugTargetPane(
+ runtime.runtimeDetails.info.type,
+ DEBUG_TARGET_PANE.TAB
+ );
+ const tabs = isSupported ? await clientWrapper.listTabs() : [];
+
+ // Fetch the favicon for all tabs.
+ await Promise.all(
+ tabs.map(descriptorFront => descriptorFront.retrieveFavicon())
+ );
+
+ dispatch({ type: REQUEST_TABS_SUCCESS, tabs });
+ } catch (e) {
+ dispatch({ type: REQUEST_TABS_FAILURE, error: e });
+ }
+ };
+}
+
+function requestExtensions() {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: REQUEST_EXTENSIONS_START });
+
+ const runtime = getCurrentRuntime(getState().runtimes);
+ const clientWrapper = getCurrentClient(getState().runtimes);
+
+ try {
+ const isIconDataURLRequired = runtime.type !== RUNTIMES.THIS_FIREFOX;
+ const addons = await clientWrapper.listAddons({
+ iconDataURL: isIconDataURLRequired,
+ });
+
+ const showHiddenAddons = getState().ui.showHiddenAddons;
+
+ // Filter out non-debuggable addons as well as hidden ones, unless the dedicated
+ // preference is set to true.
+ const extensions = addons.filter(
+ a => a.debuggable && (!a.hidden || showHiddenAddons)
+ );
+
+ const installedExtensions = extensions.filter(
+ e => !e.temporarilyInstalled
+ );
+ const temporaryExtensions = extensions.filter(
+ e => e.temporarilyInstalled
+ );
+
+ dispatch({
+ type: REQUEST_EXTENSIONS_SUCCESS,
+ installedExtensions,
+ temporaryExtensions,
+ });
+ } catch (e) {
+ dispatch({ type: REQUEST_EXTENSIONS_FAILURE, error: e });
+ }
+ };
+}
+
+function requestProcesses() {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: REQUEST_PROCESSES_START });
+
+ const clientWrapper = getCurrentClient(getState().runtimes);
+
+ try {
+ const mainProcessDescriptorFront = await clientWrapper.getMainProcess();
+ dispatch({
+ type: REQUEST_PROCESSES_SUCCESS,
+ mainProcess: {
+ id: 0,
+ processFront: mainProcessDescriptorFront,
+ },
+ });
+ } catch (e) {
+ dispatch({ type: REQUEST_PROCESSES_FAILURE, error: e });
+ }
+ };
+}
+
+function requestWorkers() {
+ return async ({ dispatch, getState }) => {
+ dispatch({ type: REQUEST_WORKERS_START });
+
+ const clientWrapper = getCurrentClient(getState().runtimes);
+
+ try {
+ const { otherWorkers, serviceWorkers, sharedWorkers } =
+ await clientWrapper.listWorkers();
+
+ for (const serviceWorker of serviceWorkers) {
+ const { registrationFront } = serviceWorker;
+ if (!registrationFront) {
+ continue;
+ }
+
+ const subscription = await registrationFront.getPushSubscription();
+ serviceWorker.subscription = subscription;
+ }
+
+ dispatch({
+ type: REQUEST_WORKERS_SUCCESS,
+ otherWorkers,
+ serviceWorkers,
+ sharedWorkers,
+ });
+ } catch (e) {
+ dispatch({ type: REQUEST_WORKERS_FAILURE, error: e });
+ }
+ };
+}
+
+function startServiceWorker(registrationFront) {
+ return async () => {
+ try {
+ await registrationFront.start();
+ } catch (e) {
+ console.error(e);
+ }
+ };
+}
+
+function unregisterServiceWorker(registrationFront) {
+ return async () => {
+ try {
+ await registrationFront.unregister();
+ } catch (e) {
+ console.error(e);
+ }
+ };
+}
+
+module.exports = {
+ inspectDebugTarget,
+ installTemporaryExtension,
+ pushServiceWorker,
+ reloadTemporaryExtension,
+ removeTemporaryExtension,
+ requestTabs,
+ requestExtensions,
+ requestProcesses,
+ requestWorkers,
+ startServiceWorker,
+ terminateExtensionBackgroundScript,
+ unregisterServiceWorker,
+};