diff options
Diffstat (limited to 'devtools/client/webide/modules/runtimes.js')
-rw-r--r-- | devtools/client/webide/modules/runtimes.js | 673 |
1 files changed, 0 insertions, 673 deletions
diff --git a/devtools/client/webide/modules/runtimes.js b/devtools/client/webide/modules/runtimes.js deleted file mode 100644 index a23337359..000000000 --- a/devtools/client/webide/modules/runtimes.js +++ /dev/null @@ -1,673 +0,0 @@ -/* 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 Services = require("Services"); -const {Devices} = require("resource://devtools/shared/apps/Devices.jsm"); -const {Connection} = require("devtools/shared/client/connection-manager"); -const {DebuggerServer} = require("devtools/server/main"); -const {Simulators} = require("devtools/client/webide/modules/simulators"); -const discovery = require("devtools/shared/discovery/discovery"); -const EventEmitter = require("devtools/shared/event-emitter"); -const promise = require("promise"); -loader.lazyRequireGetter(this, "AuthenticationResult", - "devtools/shared/security/auth", true); -loader.lazyRequireGetter(this, "DevToolsUtils", - "devtools/shared/DevToolsUtils"); - -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -/** - * Runtime and Scanner API - * - * |RuntimeScanners| maintains a set of |Scanner| objects that produce one or - * more |Runtime|s to connect to. Add-ons can extend the set of known runtimes - * by registering additional |Scanner|s that emit them. - * - * Each |Scanner| must support the following API: - * - * enable() - * Bind any event handlers and start any background work the scanner needs to - * maintain an updated set of |Runtime|s. - * Called when the first consumer (such as WebIDE) actively interested in - * maintaining the |Runtime| list enables the registry. - * disable() - * Unbind any event handlers and stop any background work the scanner needs to - * maintain an updated set of |Runtime|s. - * Called when the last consumer (such as WebIDE) actively interested in - * maintaining the |Runtime| list disables the registry. - * emits "runtime-list-updated" - * If the set of runtimes a |Scanner| manages has changed, it must emit this - * event to notify consumers of changes. - * scan() - * Actively refreshes the list of runtimes the scanner knows about. If your - * scanner uses an active scanning approach (as opposed to listening for - * events when changes occur), the bulk of the work would be done here. - * @return Promise - * Should be resolved when scanning is complete. If scanning has no - * well-defined end point, you can resolve immediately, as long as - * update event is emitted later when changes are noticed. - * listRuntimes() - * Return the current list of runtimes known to the |Scanner| instance. - * @return Iterable - * - * Each |Runtime| must support the following API: - * - * |type| field - * The |type| must be one of the values from the |RuntimeTypes| object. This - * is used for Telemetry and to support displaying sets of |Runtime|s - * categorized by type. - * |id| field - * An identifier that is unique in the set of all runtimes with the same - * |type|. WebIDE tries to save the last used runtime via type + id, and - * tries to locate it again in the next session, so this value should attempt - * to be stable across Firefox sessions. - * |name| field - * A user-visible label to identify the runtime that will be displayed in a - * runtime list. - * |prolongedConnection| field - * A boolean value which should be |true| if the connection process is - * expected to take a unknown or large amount of time. A UI may use this as a - * hint to skip timeouts or other time-based code paths. - * connect() - * Configure the passed |connection| object with any settings need to - * successfully connect to the runtime, and call the |connection|'s connect() - * method. - * @param Connection connection - * A |Connection| object from the DevTools |ConnectionManager|. - * @return Promise - * Resolved once you've called the |connection|'s connect() method. - * configure() OPTIONAL - * Show a configuration screen if the runtime is configurable. - */ - -/* SCANNER REGISTRY */ - -var RuntimeScanners = { - - _enabledCount: 0, - _scanners: new Set(), - - get enabled() { - return !!this._enabledCount; - }, - - add(scanner) { - if (this.enabled) { - // Enable any scanner added while globally enabled - this._enableScanner(scanner); - } - this._scanners.add(scanner); - this._emitUpdated(); - }, - - remove(scanner) { - this._scanners.delete(scanner); - if (this.enabled) { - // Disable any scanner removed while globally enabled - this._disableScanner(scanner); - } - this._emitUpdated(); - }, - - has(scanner) { - return this._scanners.has(scanner); - }, - - scan() { - if (!this.enabled) { - return promise.resolve(); - } - - if (this._scanPromise) { - return this._scanPromise; - } - - let promises = []; - - for (let scanner of this._scanners) { - promises.push(scanner.scan()); - } - - this._scanPromise = promise.all(promises); - - // Reset pending promise - this._scanPromise.then(() => { - this._scanPromise = null; - }, () => { - this._scanPromise = null; - }); - - return this._scanPromise; - }, - - listRuntimes: function* () { - for (let scanner of this._scanners) { - for (let runtime of scanner.listRuntimes()) { - yield runtime; - } - } - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - enable() { - if (this._enabledCount++ !== 0) { - // Already enabled scanners during a previous call - return; - } - this._emitUpdated = this._emitUpdated.bind(this); - for (let scanner of this._scanners) { - this._enableScanner(scanner); - } - }, - - _enableScanner(scanner) { - scanner.enable(); - scanner.on("runtime-list-updated", this._emitUpdated); - }, - - disable() { - if (--this._enabledCount !== 0) { - // Already disabled scanners during a previous call - return; - } - for (let scanner of this._scanners) { - this._disableScanner(scanner); - } - }, - - _disableScanner(scanner) { - scanner.off("runtime-list-updated", this._emitUpdated); - scanner.disable(); - }, - -}; - -EventEmitter.decorate(RuntimeScanners); - -exports.RuntimeScanners = RuntimeScanners; - -/* SCANNERS */ - -var SimulatorScanner = { - - _runtimes: [], - - enable() { - this._updateRuntimes = this._updateRuntimes.bind(this); - Simulators.on("updated", this._updateRuntimes); - this._updateRuntimes(); - }, - - disable() { - Simulators.off("updated", this._updateRuntimes); - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - _updateRuntimes() { - Simulators.findSimulators().then(simulators => { - this._runtimes = []; - for (let simulator of simulators) { - this._runtimes.push(new SimulatorRuntime(simulator)); - } - this._emitUpdated(); - }); - }, - - scan() { - return promise.resolve(); - }, - - listRuntimes: function () { - return this._runtimes; - } - -}; - -EventEmitter.decorate(SimulatorScanner); -RuntimeScanners.add(SimulatorScanner); - -/** - * TODO: Remove this comaptibility layer in the future (bug 1085393) - * This runtime exists to support the ADB Helper add-on below version 0.7.0. - * - * This scanner will list all ADB devices as runtimes, even if they may or may - * not actually connect (since the |DeprecatedUSBRuntime| assumes a Firefox OS - * device). - */ -var DeprecatedAdbScanner = { - - _runtimes: [], - - enable() { - this._updateRuntimes = this._updateRuntimes.bind(this); - Devices.on("register", this._updateRuntimes); - Devices.on("unregister", this._updateRuntimes); - Devices.on("addon-status-updated", this._updateRuntimes); - this._updateRuntimes(); - }, - - disable() { - Devices.off("register", this._updateRuntimes); - Devices.off("unregister", this._updateRuntimes); - Devices.off("addon-status-updated", this._updateRuntimes); - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - _updateRuntimes() { - this._runtimes = []; - for (let id of Devices.available()) { - let runtime = new DeprecatedUSBRuntime(id); - this._runtimes.push(runtime); - runtime.updateNameFromADB().then(() => { - this._emitUpdated(); - }, () => {}); - } - this._emitUpdated(); - }, - - scan() { - return promise.resolve(); - }, - - listRuntimes: function () { - return this._runtimes; - } - -}; - -EventEmitter.decorate(DeprecatedAdbScanner); -RuntimeScanners.add(DeprecatedAdbScanner); - -// ADB Helper 0.7.0 and later will replace this scanner on startup -exports.DeprecatedAdbScanner = DeprecatedAdbScanner; - -/** - * This is a lazy ADB scanner shim which only tells the ADB Helper to start and - * stop as needed. The real scanner that lists devices lives in ADB Helper. - * ADB Helper 0.8.0 and later wait until these signals are received before - * starting ADB polling. For earlier versions, they have no effect. - */ -var LazyAdbScanner = { - - enable() { - Devices.emit("adb-start-polling"); - }, - - disable() { - Devices.emit("adb-stop-polling"); - }, - - scan() { - return promise.resolve(); - }, - - listRuntimes: function () { - return []; - } - -}; - -EventEmitter.decorate(LazyAdbScanner); -RuntimeScanners.add(LazyAdbScanner); - -var WiFiScanner = { - - _runtimes: [], - - init() { - this.updateRegistration(); - Services.prefs.addObserver(this.ALLOWED_PREF, this, false); - }, - - enable() { - this._updateRuntimes = this._updateRuntimes.bind(this); - discovery.on("devtools-device-added", this._updateRuntimes); - discovery.on("devtools-device-updated", this._updateRuntimes); - discovery.on("devtools-device-removed", this._updateRuntimes); - this._updateRuntimes(); - }, - - disable() { - discovery.off("devtools-device-added", this._updateRuntimes); - discovery.off("devtools-device-updated", this._updateRuntimes); - discovery.off("devtools-device-removed", this._updateRuntimes); - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - _updateRuntimes() { - this._runtimes = []; - for (let device of discovery.getRemoteDevicesWithService("devtools")) { - this._runtimes.push(new WiFiRuntime(device)); - } - this._emitUpdated(); - }, - - scan() { - discovery.scan(); - return promise.resolve(); - }, - - listRuntimes: function () { - return this._runtimes; - }, - - ALLOWED_PREF: "devtools.remote.wifi.scan", - - get allowed() { - return Services.prefs.getBoolPref(this.ALLOWED_PREF); - }, - - updateRegistration() { - if (this.allowed) { - RuntimeScanners.add(WiFiScanner); - } else { - RuntimeScanners.remove(WiFiScanner); - } - this._emitUpdated(); - }, - - observe(subject, topic, data) { - if (data !== WiFiScanner.ALLOWED_PREF) { - return; - } - WiFiScanner.updateRegistration(); - } - -}; - -EventEmitter.decorate(WiFiScanner); -WiFiScanner.init(); - -exports.WiFiScanner = WiFiScanner; - -var StaticScanner = { - enable() {}, - disable() {}, - scan() { return promise.resolve(); }, - listRuntimes() { - let runtimes = [gRemoteRuntime]; - if (Services.prefs.getBoolPref("devtools.webide.enableLocalRuntime")) { - runtimes.push(gLocalRuntime); - } - return runtimes; - } -}; - -EventEmitter.decorate(StaticScanner); -RuntimeScanners.add(StaticScanner); - -/* RUNTIMES */ - -// These type strings are used for logging events to Telemetry. -// You must update Histograms.json if new types are added. -var RuntimeTypes = exports.RuntimeTypes = { - USB: "USB", - WIFI: "WIFI", - SIMULATOR: "SIMULATOR", - REMOTE: "REMOTE", - LOCAL: "LOCAL", - OTHER: "OTHER" -}; - -/** - * TODO: Remove this comaptibility layer in the future (bug 1085393) - * This runtime exists to support the ADB Helper add-on below version 0.7.0. - * - * This runtime assumes it is connecting to a Firefox OS device. - */ -function DeprecatedUSBRuntime(id) { - this._id = id; -} - -DeprecatedUSBRuntime.prototype = { - type: RuntimeTypes.USB, - get device() { - return Devices.getByName(this._id); - }, - connect: function (connection) { - if (!this.device) { - return promise.reject(new Error("Can't find device: " + this.name)); - } - return this.device.connect().then((port) => { - connection.host = "localhost"; - connection.port = port; - connection.connect(); - }); - }, - get id() { - return this._id; - }, - get name() { - return this._productModel || this._id; - }, - updateNameFromADB: function () { - if (this._productModel) { - return promise.reject(); - } - let deferred = promise.defer(); - if (this.device && this.device.shell) { - this.device.shell("getprop ro.product.model").then(stdout => { - this._productModel = stdout; - deferred.resolve(); - }, () => {}); - } else { - this._productModel = null; - deferred.reject(); - } - return deferred.promise; - }, -}; - -// For testing use only -exports._DeprecatedUSBRuntime = DeprecatedUSBRuntime; - -function WiFiRuntime(deviceName) { - this.deviceName = deviceName; -} - -WiFiRuntime.prototype = { - type: RuntimeTypes.WIFI, - // Mark runtime as taking a long time to connect - prolongedConnection: true, - connect: function (connection) { - let service = discovery.getRemoteService("devtools", this.deviceName); - if (!service) { - return promise.reject(new Error("Can't find device: " + this.name)); - } - connection.advertisement = service; - connection.authenticator.sendOOB = this.sendOOB; - // Disable the default connection timeout, since QR scanning can take an - // unknown amount of time. This prevents spurious errors (even after - // eventual success) from being shown. - connection.timeoutDelay = 0; - connection.connect(); - return promise.resolve(); - }, - get id() { - return this.deviceName; - }, - get name() { - return this.deviceName; - }, - - /** - * During OOB_CERT authentication, a notification dialog like this is used to - * to display a token which the user must transfer through some mechanism to the - * server to authenticate the devices. - * - * This implementation presents the token as text for the user to transfer - * manually. For a mobile device, you should override this implementation with - * something more convenient, such as displaying a QR code. - * - * This method receives an object containing: - * @param host string - * The host name or IP address of the debugger server. - * @param port number - * The port number of the debugger server. - * @param cert object (optional) - * The server's cert details. - * @param authResult AuthenticationResult - * Authentication result sent from the server. - * @param oob object (optional) - * The token data to be transferred during OOB_CERT step 8: - * * sha256: hash(ClientCert) - * * k : K(random 128-bit number) - * @return object containing: - * * close: Function to hide the notification - */ - sendOOB(session) { - const WINDOW_ID = "devtools:wifi-auth"; - let { authResult } = session; - // Only show in the PENDING state - if (authResult != AuthenticationResult.PENDING) { - throw new Error("Expected PENDING result, got " + authResult); - } - - // Listen for the window our prompt opens, so we can close it programatically - let promptWindow; - let windowListener = { - onOpenWindow(xulWindow) { - let win = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); - win.addEventListener("load", function listener() { - win.removeEventListener("load", listener, false); - if (win.document.documentElement.getAttribute("id") != WINDOW_ID) { - return; - } - // Found the window - promptWindow = win; - Services.wm.removeListener(windowListener); - }, false); - }, - onCloseWindow() {}, - onWindowTitleChange() {} - }; - Services.wm.addListener(windowListener); - - // |openDialog| is typically a blocking API, so |executeSoon| to get around this - DevToolsUtils.executeSoon(() => { - // Height determines the size of the QR code. Force a minimum size to - // improve scanability. - const MIN_HEIGHT = 600; - let win = Services.wm.getMostRecentWindow("devtools:webide"); - let width = win.outerWidth * 0.8; - let height = Math.max(win.outerHeight * 0.5, MIN_HEIGHT); - win.openDialog("chrome://webide/content/wifi-auth.xhtml", - WINDOW_ID, - "modal=yes,width=" + width + ",height=" + height, session); - }); - - return { - close() { - if (!promptWindow) { - return; - } - promptWindow.close(); - promptWindow = null; - } - }; - } -}; - -// For testing use only -exports._WiFiRuntime = WiFiRuntime; - -function SimulatorRuntime(simulator) { - this.simulator = simulator; -} - -SimulatorRuntime.prototype = { - type: RuntimeTypes.SIMULATOR, - connect: function (connection) { - return this.simulator.launch().then(port => { - connection.host = "localhost"; - connection.port = port; - connection.keepConnecting = true; - connection.once(Connection.Events.DISCONNECTED, e => this.simulator.kill()); - connection.connect(); - }); - }, - configure() { - Simulators.emit("configure", this.simulator); - }, - get id() { - return this.simulator.id; - }, - get name() { - return this.simulator.name; - }, -}; - -// For testing use only -exports._SimulatorRuntime = SimulatorRuntime; - -var gLocalRuntime = { - type: RuntimeTypes.LOCAL, - connect: function (connection) { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - DebuggerServer.allowChromeProcess = true; - connection.host = null; // Force Pipe transport - connection.port = null; - connection.connect(); - return promise.resolve(); - }, - get id() { - return "local"; - }, - get name() { - return Strings.GetStringFromName("local_runtime"); - }, -}; - -// For testing use only -exports._gLocalRuntime = gLocalRuntime; - -var gRemoteRuntime = { - type: RuntimeTypes.REMOTE, - connect: function (connection) { - let win = Services.wm.getMostRecentWindow("devtools:webide"); - if (!win) { - return promise.reject(new Error("No WebIDE window found")); - } - let ret = {value: connection.host + ":" + connection.port}; - let title = Strings.GetStringFromName("remote_runtime_promptTitle"); - let message = Strings.GetStringFromName("remote_runtime_promptMessage"); - let ok = Services.prompt.prompt(win, title, message, ret, null, {}); - let [host, port] = ret.value.split(":"); - if (!ok) { - return promise.reject({canceled: true}); - } - if (!host || !port) { - return promise.reject(new Error("Invalid host or port")); - } - connection.host = host; - connection.port = port; - connection.connect(); - return promise.resolve(); - }, - get name() { - return Strings.GetStringFromName("remote_runtime"); - }, -}; - -// For testing use only -exports._gRemoteRuntime = gRemoteRuntime; |