Bug 1243329 - [WIP] Fold the 'Connect' screen into about:debugging.
MozReview-Commit-ID: 53hJgHXEXqD
--- a/devtools/client/aboutdebugging/components/aboutdebugging.js
+++ b/devtools/client/aboutdebugging/components/aboutdebugging.js
@@ -3,26 +3,36 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env browser */
"use strict";
const { createFactory, createClass, DOM: dom } =
require("devtools/client/shared/vendor/react");
+const { ConnectionManager, Connection } =
+ require("devtools/shared/client/connection-manager");
+const { RuntimeScanners } = require("devtools/client/webide/modules/runtimes");
const Services = require("Services");
+loader.lazyRequireGetter(this, "DebuggerClient",
+ "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "DebuggerServer",
+ "devtools/server/main", true);
+
const PanelMenu = createFactory(require("./panel-menu"));
loader.lazyGetter(this, "AddonsPanel",
() => createFactory(require("./addons/panel")));
loader.lazyGetter(this, "TabsPanel",
() => createFactory(require("./tabs/panel")));
loader.lazyGetter(this, "WorkersPanel",
() => createFactory(require("./workers/panel")));
+loader.lazyGetter(this, "ConnectPanel",
+ () => createFactory(require("./connect-panel")));
const Strings = Services.strings.createBundle(
"chrome://devtools/locale/aboutdebugging.properties");
const panels = [{
id: "addons",
name: Strings.GetStringFromName("addons"),
icon: "chrome://devtools/skin/images/debugging-addons.svg",
@@ -32,53 +42,145 @@ const panels = [{
name: Strings.GetStringFromName("tabs"),
icon: "chrome://devtools/skin/images/debugging-tabs.svg",
component: TabsPanel
}, {
id: "workers",
name: Strings.GetStringFromName("workers"),
icon: "chrome://devtools/skin/images/debugging-workers.svg",
component: WorkersPanel
+}, {
+ id: "connect",
+ name: "Connect",
+ component: ConnectPanel
}];
const defaultPanelId = "addons";
+// TODO: Refactor this as a shared devtools module.
+function findDebuggerTransport(href) {
+
+ // URL constructor doesn't support about: scheme
+ let url = new window.URL(href.replace("about:", "http://"));
+
+ // No query parameters -> local debugging
+ // about:debugging
+ if (url.search.length <= 1) {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+ DebuggerServer.allowChromeProcess = true;
+ return Promise.resolve(DebuggerServer.connectPipe());
+ }
+
+ let params = url.searchParams;
+
+ // Remote debugging: host + port
+ // about:debugging?host=localhost&port=9000
+ if (params.has("host") && params.has("port")) {
+ let host = params.get("host");
+ let port = params.get("port");
+
+ // Copy/pasted from /devtools/client/framework/connect/connect.js :
+ try {
+ Services.prefs.setCharPref("devtools.debugger.remote-host", host);
+ Services.prefs.setIntPref("devtools.debugger.remote-port", port);
+ } catch (e) {
+ // Fails in e10s mode, but not a critical feature.
+ }
+ return DebuggerClient.socketConnect({ host, port });
+ }
+
+ // Remote debugging: USB/WiFi device
+ if (params.has("runtime") && params.has("type")) {
+ let id = params.get("runtime");
+ let type = params.get("type");
+ for (let runtime of RuntimeScanners.listRuntimes()) {
+ if (runtime.id !== id || runtime.type !== type) {
+ continue;
+ }
+ // Adapted from /devtools/client/webide/modules/app-manager.js:
+ // FIXME: This is probably not the right way to do this.
+ let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
+ let connection = ConnectionManager.createConnection("localhost", port);
+ connection.off(Connection.Events.CONNECTED, () => {});
+ connection.off(Connection.Events.DISCONNECTED, () => {});
+ connection.resetOptions();
+ runtime.connect(connection);
+ return Promise.resolve(connection.client._transport);
+ }
+ return Promise.reject(new Error("Couldn't find runtime with spec: " + url.search));
+ }
+
+ // Unsupported runtime spec
+ // about:debugging?hello=world
+ return Promise.reject(new Error("Invalid runtime spec: " + url.search));
+
+}
+
module.exports = createClass({
displayName: "AboutDebuggingApp",
getInitialState() {
return {
+ client: null,
+ error: null,
selectedPanelId: defaultPanelId
};
},
componentDidMount() {
+ dump("@@@@ getting runtime transport from spec...\n");
+ findDebuggerTransport(window.location.href).then(transport => {
+ dump("@@@@ creating DebuggerClient...\n");
+ let client = new DebuggerClient(transport);
+ dump("@@@@ connecting...\n");
+ client.connect().then(() => {
+ dump("@@@@ connected! \\o/\n");
+ this.setState({ client });
+ });
+ }).catch(error => {
+ dump("@@@@ error: " + error + "\n");
+ this.setState({ error });
+ });
window.addEventListener("hashchange", this.onHashChange);
this.onHashChange();
this.props.telemetry.toolOpened("aboutdebugging");
},
componentWillUnmount() {
+ let { client } = this.state;
+ if (client) {
+ client.close();
+ }
window.removeEventListener("hashchange", this.onHashChange);
this.props.telemetry.toolClosed("aboutdebugging");
this.props.telemetry.destroy();
},
onHashChange() {
this.setState({
selectedPanelId: window.location.hash.substr(1) || defaultPanelId
});
},
selectPanel(panelId) {
window.location.hash = "#" + panelId;
},
render() {
- let { client } = this.props;
+ let { client, error } = this.state;
+ if (error) {
+ return dom.pre(null, "Error: " + error);
+ }
+ if (!client) {
+ return dom.pre(null, "Connecting...")
+ }
+
let { selectedPanelId } = this.state;
let selectPanel = this.selectPanel;
let selectedPanel = panels.find(p => p.id == selectedPanelId);
let panel;
if (selectedPanel) {
panel = selectedPanel.component({ client, id: selectedPanel.id });
} else {
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/components/connect-panel.js
@@ -0,0 +1,125 @@
+/* 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/. */
+
+/* eslint-env browser */
+
+"use strict";
+
+const { createClass, createFactory, DOM: dom } =
+ require("devtools/client/shared/vendor/react");
+const Services = require("Services");
+const { RuntimeScanners, RuntimeTypes } = require("devtools/client/webide/modules/runtimes");
+
+const PanelHeader = createFactory(require("./panel-header"));
+
+const Strings = Services.strings.createBundle(
+ "chrome://devtools/locale/aboutdebugging.properties");
+
+module.exports = createClass({
+ displayName: "ConnectPanel",
+
+ getInitialState() {
+ return {
+ runtimes: {
+ usb: [],
+ wifi: [],
+ simulators: [],
+ other: []
+ }
+ };
+ },
+
+ componentDidMount() {
+ RuntimeScanners.on("runtime-list-updated", this.update);
+ RuntimeScanners.enable();
+ this.update();
+ },
+
+ componentWillUnmount() {
+ RuntimeScanners.off("runtime-list-updated", this.update);
+ RuntimeScanners.disable();
+ },
+
+ update() {
+ let runtimes = this.getInitialState().runtimes;
+ for (let runtime of RuntimeScanners.listRuntimes()) {
+ switch (runtime.type) {
+ case RuntimeTypes.USB:
+ runtimes.usb.push(runtime);
+ break;
+ case RuntimeTypes.WIFI:
+ runtimes.wifi.push(runtime);
+ break;
+ case RuntimeTypes.SIMULATOR:
+ runtimes.simulators.push(runtime);
+ break;
+ default:
+ runtimes.other.push(runtime);
+ }
+ }
+ this.setState({ runtimes });
+ },
+
+ render() {
+ let { id } = this.props;
+ let { runtimes } = this.state;
+
+ // TODO: Maybe render "Enable remote debugging" pref checkbox?
+
+ // TODO: Refactor this a React component.
+ function runtimeLink (runtime) {
+ return dom.a({
+ href: "about:debugging?runtime=" + runtime.id + "&type=" + runtime.type,
+ style: { display: "block" },
+ target: "_blank",
+ title: "Connect to " + runtime.name
+ }, runtime.name);
+ }
+
+ return dom.div({
+ id: id + "-panel",
+ className: "panel",
+ role: "tabpanel",
+ "aria-labelledby": id + "-header"
+ },
+ PanelHeader({
+ id: id + "-header",
+ name: "Connect"
+ }),
+ dom.div({},
+ dom.h2({}, "USB devices"),
+ (runtimes.usb.length > 0
+ ? runtimes.usb.map(runtimeLink)
+ : "Nothing yet."),
+ dom.h2({}, "WiFi devices"),
+ (runtimes.wifi.length > 0
+ ? runtimes.wifi.map(runtimeLink)
+ : "Nothing yet."),
+ dom.h2({}, "Firefox OS simulators"),
+ (runtimes.simulators.length > 0
+ ? runtimes.simulators.map(runtimeLink)
+ : "Nothing yet."),
+ dom.h2({}, "Other runtimes"),
+ (runtimes.other.length > 0
+ ? runtimes.other.map(runtimeLink)
+ : "Nothing yet."),
+ dom.h2({}, "Remote runtime"),
+ dom.form({ target: "_blank" },
+ dom.span({}, "Host:"),
+ dom.input({
+ name: "host",
+ placeholder: "(try localhost)",
+ style: { display: "inline" }
+ }),
+ dom.span({}, "Port:"),
+ dom.input({
+ name: "port",
+ placeholder: "(try 6080)",
+ style: { display: "inline" }
+ }),
+ dom.button({}, "Connect")
+ )
+ ));
+ }
+});
--- a/devtools/client/aboutdebugging/components/moz.build
+++ b/devtools/client/aboutdebugging/components/moz.build
@@ -5,13 +5,14 @@
DIRS += [
'addons',
'tabs',
'workers',
]
DevToolsModules(
'aboutdebugging.js',
+ 'connect-panel.js',
'panel-header.js',
'panel-menu-entry.js',
'panel-menu.js',
'target-list.js',
)
--- a/devtools/client/aboutdebugging/initializer.js
+++ b/devtools/client/aboutdebugging/initializer.js
@@ -1,63 +1,44 @@
/* 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/. */
/* eslint-env browser */
-/* globals DebuggerClient, DebuggerServer, Telemetry */
+/* globals Telemetry */
"use strict";
const { loader } = Components.utils.import(
"resource://devtools/shared/Loader.jsm", {});
const { BrowserLoader } = Components.utils.import(
"resource://devtools/client/shared/browser-loader.js", {});
-loader.lazyRequireGetter(this, "DebuggerClient",
- "devtools/shared/client/main", true);
-loader.lazyRequireGetter(this, "DebuggerServer",
- "devtools/server/main", true);
loader.lazyRequireGetter(this, "Telemetry",
"devtools/client/shared/telemetry");
const { require } = BrowserLoader({
baseURI: "resource://devtools/client/aboutdebugging/",
window
});
const { createFactory, render, unmountComponentAtNode } =
require("devtools/client/shared/vendor/react");
const AboutDebuggingApp = createFactory(require("./components/aboutdebugging"));
var AboutDebugging = {
init() {
- if (!DebuggerServer.initialized) {
- DebuggerServer.init();
- DebuggerServer.addBrowserActors();
- }
- DebuggerServer.allowChromeProcess = true;
-
- this.client = new DebuggerClient(DebuggerServer.connectPipe());
-
- this.client.connect().then(() => {
- let client = this.client;
- let telemetry = new Telemetry();
-
- render(AboutDebuggingApp({ client, telemetry }),
- document.querySelector("#body"));
- });
+ let telemetry = new Telemetry();
+ render(AboutDebuggingApp({ telemetry }),
+ document.querySelector("#body"));
},
destroy() {
unmountComponentAtNode(document.querySelector("#body"));
-
- this.client.close();
- this.client = null;
},
};
window.addEventListener("DOMContentLoaded", function load() {
window.removeEventListener("DOMContentLoaded", load);
AboutDebugging.init();
});