summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/lib/sdk/remote
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2018-02-09 06:46:43 -0500
committerMatt A. Tobin <email@mattatobin.com>2018-02-09 06:46:43 -0500
commitac46df8daea09899ce30dc8fd70986e258c746bf (patch)
tree2750d3125fc253fd5b0671e4bd268eff1fd97296 /addon-sdk/source/lib/sdk/remote
parent8cecf8d5208f3945b35f879bba3015bb1a11bec6 (diff)
downloadUXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.gz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.lz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.tar.xz
UXP-ac46df8daea09899ce30dc8fd70986e258c746bf.zip
Move Add-on SDK source to toolkit/jetpack
Diffstat (limited to 'addon-sdk/source/lib/sdk/remote')
-rw-r--r--addon-sdk/source/lib/sdk/remote/child.js284
-rw-r--r--addon-sdk/source/lib/sdk/remote/core.js8
-rw-r--r--addon-sdk/source/lib/sdk/remote/parent.js338
-rw-r--r--addon-sdk/source/lib/sdk/remote/utils.js39
4 files changed, 0 insertions, 669 deletions
diff --git a/addon-sdk/source/lib/sdk/remote/child.js b/addon-sdk/source/lib/sdk/remote/child.js
deleted file mode 100644
index 4ccfa661a..000000000
--- a/addon-sdk/source/lib/sdk/remote/child.js
+++ /dev/null
@@ -1,284 +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 { isChildLoader } = require('./core');
-if (!isChildLoader)
- throw new Error("Cannot load sdk/remote/child in a main process loader.");
-
-const { Ci, Cc, Cu } = require('chrome');
-const runtime = require('../system/runtime');
-const { Class } = require('../core/heritage');
-const { Namespace } = require('../core/namespace');
-const { omit } = require('../util/object');
-const { when } = require('../system/unload');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const { Disposable } = require('../core/disposable');
-const { EventParent } = require('./utils');
-const { addListItem, removeListItem } = require('../util/list');
-
-const loaderID = require('@loader/options').loaderID;
-
-const MAIN_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-
-const mm = Cc['@mozilla.org/childprocessmessagemanager;1'].
- getService(Ci.nsISyncMessageSender);
-
-const ns = Namespace();
-
-const process = {
- port: new EventTarget(),
- get id() {
- return runtime.processID;
- },
- get isRemote() {
- return runtime.processType != MAIN_PROCESS;
- }
-};
-exports.process = process;
-
-function definePort(obj, name) {
- obj.port.emit = (event, ...args) => {
- let manager = ns(obj).messageManager;
- if (!manager)
- return;
-
- manager.sendAsyncMessage(name, { loaderID, event, args });
- };
-}
-
-function messageReceived({ data, objects }) {
- // Ignore messages from other loaders
- if (data.loaderID != loaderID)
- return;
-
- let keys = Object.keys(objects);
- if (keys.length) {
- // If any objects are CPOWs then ignore this message. We don't want child
- // processes interracting with CPOWs
- if (!keys.every(name => !Cu.isCrossProcessWrapper(objects[name])))
- return;
-
- data.args.push(objects);
- }
-
- emit(this.port, data.event, this, ...data.args);
-}
-
-ns(process).messageManager = mm;
-definePort(process, 'sdk/remote/process/message');
-let processMessageReceived = messageReceived.bind(process);
-mm.addMessageListener('sdk/remote/process/message', processMessageReceived);
-
-when(() => {
- mm.removeMessageListener('sdk/remote/process/message', processMessageReceived);
- frames = null;
-});
-
-process.port.on('sdk/remote/require', (process, uri) => {
- require(uri);
-});
-
-function listenerEquals(a, b) {
- for (let prop of ["type", "callback", "isCapturing"]) {
- if (a[prop] != b[prop])
- return false;
- }
- return true;
-}
-
-function listenerFor(type, callback, isCapturing = false) {
- return {
- type,
- callback,
- isCapturing,
- registeredCallback: undefined,
- get args() {
- return [
- this.type,
- this.registeredCallback ? this.registeredCallback : this.callback,
- this.isCapturing
- ];
- }
- };
-}
-
-function removeListenerFromArray(array, listener) {
- let index = array.findIndex(l => listenerEquals(l, listener));
- if (index < 0)
- return;
- array.splice(index, 1);
-}
-
-function getListenerFromArray(array, listener) {
- return array.find(l => listenerEquals(l, listener));
-}
-
-function arrayContainsListener(array, listener) {
- return !!getListenerFromArray(array, listener);
-}
-
-function makeFrameEventListener(frame, callback) {
- return callback.bind(frame);
-}
-
-var FRAME_ID = 0;
-var tabMap = new Map();
-
-const Frame = Class({
- implements: [ Disposable ],
- extends: EventTarget,
- setup: function(contentFrame) {
- // This ID should be unique for this loader across all processes
- let priv = ns(this);
-
- priv.id = runtime.processID + ":" + FRAME_ID++;
-
- priv.contentFrame = contentFrame;
- priv.messageManager = contentFrame;
- priv.domListeners = [];
-
- tabMap.set(contentFrame.docShell, this);
-
- priv.messageReceived = messageReceived.bind(this);
- priv.messageManager.addMessageListener('sdk/remote/frame/message', priv.messageReceived);
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/frame/message');
-
- priv.messageManager.sendAsyncMessage('sdk/remote/frame/attach', {
- loaderID,
- frameID: priv.id,
- processID: runtime.processID
- });
-
- frames.attachItem(this);
- },
-
- dispose: function() {
- let priv = ns(this);
-
- emit(this, 'detach', this);
-
- for (let listener of priv.domListeners)
- priv.contentFrame.removeEventListener(...listener.args);
-
- priv.messageManager.removeMessageListener('sdk/remote/frame/message', priv.messageReceived);
- tabMap.delete(priv.contentFrame.docShell);
- priv.contentFrame = null;
- },
-
- get content() {
- return ns(this).contentFrame.content;
- },
-
- get isTab() {
- let docShell = ns(this).contentFrame.docShell;
- if (process.isRemote) {
- // We don't want to roundtrip to the main process to get this property.
- // This hack relies on the host app having defined webBrowserChrome only
- // in frames that are part of the tabs. Since only Firefox has remote
- // processes right now and does this this works.
- let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsITabChild);
- return !!tabchild.webBrowserChrome;
- }
- else {
- // This is running in the main process so we can break out to the browser
- // And check we can find a tab for the browser element directly.
- let browser = docShell.chromeEventHandler;
- let tab = require('../tabs/utils').getTabForBrowser(browser);
- return !!tab;
- }
- },
-
- addEventListener: function(...args) {
- let priv = ns(this);
-
- let listener = listenerFor(...args);
- if (arrayContainsListener(priv.domListeners, listener))
- return;
-
- listener.registeredCallback = makeFrameEventListener(this, listener.callback);
-
- priv.domListeners.push(listener);
- priv.contentFrame.addEventListener(...listener.args);
- },
-
- removeEventListener: function(...args) {
- let priv = ns(this);
-
- let listener = getListenerFromArray(priv.domListeners, listenerFor(...args));
- if (!listener)
- return;
-
- removeListenerFromArray(priv.domListeners, listener);
- priv.contentFrame.removeEventListener(...listener.args);
- }
-});
-
-const FrameList = Class({
- implements: [ EventParent, Disposable ],
- extends: EventTarget,
- setup: function() {
- EventParent.prototype.initialize.call(this);
-
- this.port = new EventTarget();
- ns(this).domListeners = [];
-
- this.on('attach', frame => {
- for (let listener of ns(this).domListeners)
- frame.addEventListener(...listener.args);
- });
- },
-
- dispose: function() {
- // The only case where we get destroyed is when the loader is unloaded in
- // which case each frame will clean up its own event listeners.
- ns(this).domListeners = null;
- },
-
- getFrameForWindow: function(window) {
- let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDocShell);
-
- return tabMap.get(docShell) || null;
- },
-
- addEventListener: function(...args) {
- let listener = listenerFor(...args);
- if (arrayContainsListener(ns(this).domListeners, listener))
- return;
-
- ns(this).domListeners.push(listener);
- for (let frame of this)
- frame.addEventListener(...listener.args);
- },
-
- removeEventListener: function(...args) {
- let listener = listenerFor(...args);
- if (!arrayContainsListener(ns(this).domListeners, listener))
- return;
-
- removeListenerFromArray(ns(this).domListeners, listener);
- for (let frame of this)
- frame.removeEventListener(...listener.args);
- }
-});
-var frames = exports.frames = new FrameList();
-
-function registerContentFrame(contentFrame) {
- let frame = new Frame(contentFrame);
-}
-exports.registerContentFrame = registerContentFrame;
-
-function unregisterContentFrame(contentFrame) {
- let frame = tabMap.get(contentFrame.docShell);
- if (!frame)
- return;
-
- frame.destroy();
-}
-exports.unregisterContentFrame = unregisterContentFrame;
diff --git a/addon-sdk/source/lib/sdk/remote/core.js b/addon-sdk/source/lib/sdk/remote/core.js
deleted file mode 100644
index 78bb673fd..000000000
--- a/addon-sdk/source/lib/sdk/remote/core.js
+++ /dev/null
@@ -1,8 +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 options = require("@loader/options");
-
-exports.isChildLoader = options.childLoader;
diff --git a/addon-sdk/source/lib/sdk/remote/parent.js b/addon-sdk/source/lib/sdk/remote/parent.js
deleted file mode 100644
index f110fe3f6..000000000
--- a/addon-sdk/source/lib/sdk/remote/parent.js
+++ /dev/null
@@ -1,338 +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 { isChildLoader } = require('./core');
-if (isChildLoader)
- throw new Error("Cannot load sdk/remote/parent in a child loader.");
-
-const { Cu, Ci, Cc } = require('chrome');
-const runtime = require('../system/runtime');
-
-const MAIN_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-
-if (runtime.processType != MAIN_PROCESS) {
- throw new Error('Cannot use sdk/remote/parent in a child process.');
-}
-
-const { Class } = require('../core/heritage');
-const { Namespace } = require('../core/namespace');
-const { Disposable } = require('../core/disposable');
-const { omit } = require('../util/object');
-const { when } = require('../system/unload');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const system = require('../system/events');
-const { EventParent } = require('./utils');
-const options = require('@loader/options');
-const loaderModule = require('toolkit/loader');
-const { getTabForBrowser } = require('../tabs/utils');
-
-const appInfo = Cc["@mozilla.org/xre/app-info;1"].
- getService(Ci.nsIXULRuntime);
-
-exports.useRemoteProcesses = appInfo.browserTabsRemoteAutostart;
-
-// Chose the right function for resolving relative a module id
-var moduleResolve;
-if (options.isNative) {
- moduleResolve = (id, requirer) => loaderModule.nodeResolve(id, requirer, { rootURI: options.rootURI });
-}
-else {
- moduleResolve = loaderModule.resolve;
-}
-// Build the sorted path mapping structure that resolveURI requires
-var pathMapping = Object.keys(options.paths)
- .sort((a, b) => b.length - a.length)
- .map(p => [p, options.paths[p]]);
-
-// Load the scripts in the child processes
-var { getNewLoaderID } = require('../../framescript/FrameScriptManager.jsm');
-var PATH = options.paths[''];
-
-const childOptions = omit(options, ['modules', 'globals', 'resolve', 'load']);
-childOptions.modules = {};
-// @l10n/data is just JSON data and can be safely sent across to the child loader
-try {
- childOptions.modules["@l10n/data"] = require("@l10n/data");
-}
-catch (e) {
- // There may be no l10n data
-}
-const loaderID = getNewLoaderID();
-childOptions.loaderID = loaderID;
-childOptions.childLoader = true;
-
-const ppmm = Cc['@mozilla.org/parentprocessmessagemanager;1'].
- getService(Ci.nsIMessageBroadcaster);
-const gmm = Cc['@mozilla.org/globalmessagemanager;1'].
- getService(Ci.nsIMessageBroadcaster);
-
-const ns = Namespace();
-
-var processMap = new Map();
-
-function definePort(obj, name) {
- obj.port.emitCPOW = (event, args, cpows = {}) => {
- let manager = ns(obj).messageManager;
- if (!manager)
- return;
-
- let method = manager instanceof Ci.nsIMessageBroadcaster ?
- "broadcastAsyncMessage" : "sendAsyncMessage";
-
- manager[method](name, { loaderID, event, args }, cpows);
- };
-
- obj.port.emit = (event, ...args) => obj.port.emitCPOW(event, args);
-}
-
-function messageReceived({ target, data }) {
- // Ignore messages from other loaders
- if (data.loaderID != loaderID)
- return;
-
- emit(this.port, data.event, this, ...data.args);
-}
-
-// Process represents a gecko process that can load webpages. Each process
-// contains a number of Frames. This class is used to send and receive messages
-// from a single process.
-const Process = Class({
- implements: [ Disposable ],
- extends: EventTarget,
- setup: function(id, messageManager, isRemote) {
- ns(this).id = id;
- ns(this).isRemote = isRemote;
- ns(this).messageManager = messageManager;
- ns(this).messageReceived = messageReceived.bind(this);
- this.destroy = this.destroy.bind(this);
- ns(this).messageManager.addMessageListener('sdk/remote/process/message', ns(this).messageReceived);
- ns(this).messageManager.addMessageListener('child-process-shutdown', this.destroy);
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/process/message');
-
- // Load any remote modules
- for (let module of remoteModules.values())
- this.port.emit('sdk/remote/require', module);
-
- processMap.set(ns(this).id, this);
- processes.attachItem(this);
- },
-
- dispose: function() {
- emit(this, 'detach', this);
- processMap.delete(ns(this).id);
- ns(this).messageManager.removeMessageListener('sdk/remote/process/message', ns(this).messageReceived);
- ns(this).messageManager.removeMessageListener('child-process-shutdown', this.destroy);
- ns(this).messageManager = null;
- },
-
- // Returns true if this process is a child process
- get isRemote() {
- return ns(this).isRemote;
- }
-});
-
-// Processes gives an API for enumerating an sending and receiving messages from
-// all processes as well as detecting when a new process starts.
-const Processes = Class({
- implements: [ EventParent ],
- extends: EventTarget,
- initialize: function() {
- EventParent.prototype.initialize.call(this);
- ns(this).messageManager = ppmm;
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/process/message');
- },
-
- getById: function(id) {
- return processMap.get(id);
- }
-});
-var processes = exports.processes = new Processes();
-
-var frameMap = new Map();
-
-function setFrameProcess(frame, process) {
- ns(frame).process = process;
- frames.attachItem(frame);
-}
-
-// Frames display webpages in a process. In the main process every Frame is
-// linked with a <browser> or <iframe> element.
-const Frame = Class({
- implements: [ Disposable ],
- extends: EventTarget,
- setup: function(id, node) {
- ns(this).id = id;
- ns(this).node = node;
-
- let frameLoader = node.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
- ns(this).messageManager = frameLoader.messageManager;
-
- ns(this).messageReceived = messageReceived.bind(this);
- ns(this).messageManager.addMessageListener('sdk/remote/frame/message', ns(this).messageReceived);
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/frame/message');
-
- frameMap.set(ns(this).messageManager, this);
- },
-
- dispose: function() {
- emit(this, 'detach', this);
- ns(this).messageManager.removeMessageListener('sdk/remote/frame/message', ns(this).messageReceived);
-
- frameMap.delete(ns(this).messageManager);
- ns(this).messageManager = null;
- },
-
- // Returns the browser or iframe element this frame displays in
- get frameElement() {
- return ns(this).node;
- },
-
- // Returns the process that this frame loads in
- get process() {
- return ns(this).process;
- },
-
- // Returns true if this frame is a tab in a main browser window
- get isTab() {
- let tab = getTabForBrowser(ns(this).node);
- return !!tab;
- }
-});
-
-function managerDisconnected({ subject: manager }) {
- let frame = frameMap.get(manager);
- if (frame)
- frame.destroy();
-}
-system.on('message-manager-disconnect', managerDisconnected);
-
-// Provides an API for enumerating and sending and receiving messages from all
-// Frames
-const FrameList = Class({
- implements: [ EventParent ],
- extends: EventTarget,
- initialize: function() {
- EventParent.prototype.initialize.call(this);
- ns(this).messageManager = gmm;
-
- this.port = new EventTarget();
- definePort(this, 'sdk/remote/frame/message');
- },
-
- // Returns the frame for a browser element
- getFrameForBrowser: function(browser) {
- for (let frame of this) {
- if (frame.frameElement == browser)
- return frame;
- }
- return null;
- },
-});
-var frames = exports.frames = new FrameList();
-
-// Create the module loader in any existing processes
-ppmm.broadcastAsyncMessage('sdk/remote/process/load', {
- modulePath: PATH,
- loaderID,
- options: childOptions,
- reason: "broadcast"
-});
-
-// A loader has started in a remote process
-function processLoaderStarted({ target, data }) {
- if (data.loaderID != loaderID)
- return;
-
- if (processMap.has(data.processID)) {
- console.error("Saw the same process load the same loader twice. This is a bug in the SDK.");
- return;
- }
-
- let process = new Process(data.processID, target, data.isRemote);
-
- if (pendingFrames.has(data.processID)) {
- for (let frame of pendingFrames.get(data.processID))
- setFrameProcess(frame, process);
- pendingFrames.delete(data.processID);
- }
-}
-
-// A new process has started
-function processStarted({ target, data: { modulePath } }) {
- if (modulePath != PATH)
- return;
-
- // Have it load a loader if it hasn't already
- target.sendAsyncMessage('sdk/remote/process/load', {
- modulePath,
- loaderID,
- options: childOptions,
- reason: "response"
- });
-}
-
-var pendingFrames = new Map();
-
-// A new frame has been created in the remote process
-function frameAttached({ target, data }) {
- if (data.loaderID != loaderID)
- return;
-
- let frame = new Frame(data.frameID, target);
-
- let process = processMap.get(data.processID);
- if (process) {
- setFrameProcess(frame, process);
- return;
- }
-
- // In some cases frame messages can arrive earlier than process messages
- // causing us to see a new frame appear before its process. In this case
- // cache the frame data until we see the process. See bug 1131375.
- if (!pendingFrames.has(data.processID))
- pendingFrames.set(data.processID, [frame]);
- else
- pendingFrames.get(data.processID).push(frame);
-}
-
-// Wait for new processes and frames
-ppmm.addMessageListener('sdk/remote/process/attach', processLoaderStarted);
-ppmm.addMessageListener('sdk/remote/process/start', processStarted);
-gmm.addMessageListener('sdk/remote/frame/attach', frameAttached);
-
-when(reason => {
- ppmm.removeMessageListener('sdk/remote/process/attach', processLoaderStarted);
- ppmm.removeMessageListener('sdk/remote/process/start', processStarted);
- gmm.removeMessageListener('sdk/remote/frame/attach', frameAttached);
-
- ppmm.broadcastAsyncMessage('sdk/remote/process/unload', { loaderID, reason });
-});
-
-var remoteModules = new Set();
-
-// Ensures a module is loaded in every child process. It is safe to send
-// messages to this module immediately after calling this.
-// Pass a module to resolve the id relatively.
-function remoteRequire(id, module = null) {
- // Resolve relative to calling module if passed
- if (module)
- id = moduleResolve(id, module.id);
- let uri = loaderModule.resolveURI(id, pathMapping);
-
- // Don't reload the same module
- if (remoteModules.has(uri))
- return;
-
- remoteModules.add(uri);
- processes.port.emit('sdk/remote/require', uri);
-}
-exports.remoteRequire = remoteRequire;
diff --git a/addon-sdk/source/lib/sdk/remote/utils.js b/addon-sdk/source/lib/sdk/remote/utils.js
deleted file mode 100644
index 5a5e39198..000000000
--- a/addon-sdk/source/lib/sdk/remote/utils.js
+++ /dev/null
@@ -1,39 +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 { Class } = require('../core/heritage');
-const { List, addListItem, removeListItem } = require('../util/list');
-const { emit } = require('../event/core');
-const { pipe } = require('../event/utils');
-
-// A helper class that maintains a list of EventTargets. Any events emitted
-// to an EventTarget are also emitted by the EventParent. Likewise for an
-// EventTarget's port property.
-const EventParent = Class({
- implements: [ List ],
-
- attachItem: function(item) {
- addListItem(this, item);
-
- pipe(item.port, this.port);
- pipe(item, this);
-
- item.once('detach', () => {
- removeListItem(this, item);
- })
-
- emit(this, 'attach', item);
- },
-
- // Calls listener for every object already in the list and every object
- // subsequently added to the list.
- forEvery: function(listener) {
- for (let item of this)
- listener(item);
-
- this.on('attach', listener);
- }
-});
-exports.EventParent = EventParent;