summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/NewTabWebChannel.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/newtab/NewTabWebChannel.jsm')
-rw-r--r--browser/components/newtab/NewTabWebChannel.jsm299
1 files changed, 0 insertions, 299 deletions
diff --git a/browser/components/newtab/NewTabWebChannel.jsm b/browser/components/newtab/NewTabWebChannel.jsm
deleted file mode 100644
index 40ee73684..000000000
--- a/browser/components/newtab/NewTabWebChannel.jsm
+++ /dev/null
@@ -1,299 +0,0 @@
-/* global
- NewTabPrefsProvider,
- Services,
- EventEmitter,
- Preferences,
- XPCOMUtils,
- WebChannel,
- NewTabRemoteResources
-*/
-/* exported NewTabWebChannel */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["NewTabWebChannel"];
-
-const {utils: Cu} = Components;
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
- "resource:///modules/NewTabPrefsProvider.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "NewTabRemoteResources",
- "resource:///modules/NewTabRemoteResources.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
- "resource://gre/modules/WebChannel.jsm");
-XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
- const {EventEmitter} = Cu.import("resource://devtools/shared/event-emitter.js", {});
- return EventEmitter;
-});
-
-const CHAN_ID = "newtab";
-const PREF_ENABLED = "browser.newtabpage.remote";
-const PREF_MODE = "browser.newtabpage.remote.mode";
-
-/**
- * NewTabWebChannel is the conduit for all communication with unprivileged newtab instances.
- *
- * It allows for the ability to broadcast to all newtab browsers.
- * If the browser.newtab.remote pref is false, the object will be in an uninitialized state.
- *
- * Mode choices:
- * 'production': pages from our production CDN
- * 'staging': pages from our staging CDN
- * 'test': intended for tests
- * 'test2': intended for tests
- * 'dev': intended for development
- *
- * An unknown mode will result in 'production' mode, which is the default
- *
- * Incoming messages are expected to be JSON-serialized and in the format:
- *
- * {
- * type: "REQUEST_SCREENSHOT",
- * data: {
- * url: "https://example.com"
- * }
- * }
- *
- * Or:
- *
- * {
- * type: "REQUEST_SCREENSHOT",
- * }
- *
- * Outgoing messages are expected to be objects serializable by structured cloning, in a similar format:
- * {
- * type: "RECEIVE_SCREENSHOT",
- * data: {
- * "url": "https://example.com",
- * "image": "dataURi:....."
- * }
- * }
- */
-let NewTabWebChannelImpl = function NewTabWebChannelImpl() {
- EventEmitter.decorate(this);
- this._handlePrefChange = this._handlePrefChange.bind(this);
- this._incomingMessage = this._incomingMessage.bind(this);
-};
-
-NewTabWebChannelImpl.prototype = {
- _prefs: {},
- _channel: null,
-
- // a WeakMap containing browsers as keys and a weak ref to their principal
- // as value
- _principals: null,
-
- // a Set containing weak refs to browsers
- _browsers: null,
-
- /*
- * Returns current channel's ID
- */
- get chanId() {
- return CHAN_ID;
- },
-
- /*
- * Returns the number of browsers currently tracking
- */
- get numBrowsers() {
- return this._getBrowserRefs().length;
- },
-
- /*
- * Returns current channel's origin
- */
- get origin() {
- if (!(this._prefs.mode in NewTabRemoteResources.MODE_CHANNEL_MAP)) {
- this._prefs.mode = "production";
- }
- return NewTabRemoteResources.MODE_CHANNEL_MAP[this._prefs.mode].origin;
- },
-
- /*
- * Unloads all browsers and principals
- */
- _unloadAll() {
- if (this._principals != null) {
- this._principals = new WeakMap();
- }
- this._browsers = new Set();
- this.emit("targetUnloadAll");
- },
-
- /*
- * Checks if a browser is known
- *
- * This will cause an iteration through all known browsers.
- * That's ok, we don't expect a lot of browsers
- */
- _isBrowserKnown(browser) {
- for (let bRef of this._getBrowserRefs()) {
- let b = bRef.get();
- if (b && b.permanentKey === browser.permanentKey) {
- return true;
- }
- }
-
- return false;
- },
-
- /*
- * Obtains all known browser refs
- */
- _getBrowserRefs() {
- // Some code may try to emit messages after teardown.
- if (!this._browsers) {
- return [];
- }
- let refs = [];
- for (let bRef of this._browsers) {
- /*
- * even though we hold a weak ref to browser, it seems that browser
- * objects aren't gc'd immediately after a tab closes. They stick around
- * in memory, but thankfully they don't have a documentURI in that case
- */
- let browser = bRef.get();
- if (browser && browser.documentURI) {
- refs.push(bRef);
- } else {
- // need to clean up principals because the browser object is not gc'ed
- // immediately
- this._principals.delete(browser);
- this._browsers.delete(bRef);
- this.emit("targetUnload");
- }
- }
- return refs;
- },
-
- /*
- * Receives a message from content.
- *
- * Keeps track of browsers for broadcast, relays messages to listeners.
- */
- _incomingMessage(id, message, target) {
- if (this.chanId !== id) {
- Cu.reportError(new Error("NewTabWebChannel unexpected message destination"));
- }
-
- /*
- * need to differentiate by browser, because event targets are created each
- * time a message is sent.
- */
- if (!this._isBrowserKnown(target.browser)) {
- this._browsers.add(Cu.getWeakReference(target.browser));
- this._principals.set(target.browser, Cu.getWeakReference(target.principal));
- this.emit("targetAdd");
- }
-
- try {
- let msg = JSON.parse(message);
- this.emit(msg.type, {data: msg.data, target: target});
- } catch (err) {
- Cu.reportError(err);
- }
- },
-
- /*
- * Sends a message to all known browsers
- */
- broadcast(actionType, message) {
- for (let bRef of this._getBrowserRefs()) {
- let browser = bRef.get();
- try {
- let principal = this._principals.get(browser).get();
- if (principal && browser && browser.documentURI) {
- this._channel.send({type: actionType, data: message}, {browser, principal});
- }
- } catch (e) {
- Cu.reportError(new Error("NewTabWebChannel WeakRef is dead"));
- this._principals.delete(browser);
- }
- }
- },
-
- /*
- * Sends a message to a specific target
- */
- send(actionType, message, target) {
- try {
- this._channel.send({type: actionType, data: message}, target);
- } catch (e) {
- // Web Channel might be dead
- Cu.reportError(e);
- }
- },
-
- /*
- * Pref change observer callback
- */
- _handlePrefChange(prefName, newState, forceState) { // eslint-disable-line no-unused-vars
- switch (prefName) {
- case PREF_ENABLED:
- if (!this._prefs.enabled && newState) {
- // changing state from disabled to enabled
- this.setupState();
- } else if (this._prefs.enabled && !newState) {
- // changing state from enabled to disabled
- this.tearDownState();
- }
- break;
- case PREF_MODE:
- if (this._prefs.mode !== newState) {
- // changing modes
- this.tearDownState();
- this.setupState();
- }
- break;
- }
- },
-
- /*
- * Sets up the internal state
- */
- setupState() {
- this._prefs.enabled = Preferences.get(PREF_ENABLED, false);
-
- let mode = Preferences.get(PREF_MODE, "production");
- if (!(mode in NewTabRemoteResources.MODE_CHANNEL_MAP)) {
- mode = "production";
- }
- this._prefs.mode = mode;
- this._principals = new WeakMap();
- this._browsers = new Set();
-
- if (this._prefs.enabled) {
- this._channel = new WebChannel(this.chanId, Services.io.newURI(this.origin, null, null));
- this._channel.listen(this._incomingMessage);
- }
- },
-
- tearDownState() {
- if (this._channel) {
- this._channel.stopListening();
- }
- this._prefs = {};
- this._unloadAll();
- this._channel = null;
- this._principals = null;
- this._browsers = null;
- },
-
- init() {
- this.setupState();
- NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handlePrefChange);
- NewTabPrefsProvider.prefs.on(PREF_MODE, this._handlePrefChange);
- },
-
- uninit() {
- this.tearDownState();
- NewTabPrefsProvider.prefs.off(PREF_ENABLED, this._handlePrefChange);
- NewTabPrefsProvider.prefs.off(PREF_MODE, this._handlePrefChange);
- }
-};
-
-let NewTabWebChannel = new NewTabWebChannelImpl();