diff options
Diffstat (limited to 'toolkit/components/webextensions/LegacyExtensionsUtils.jsm')
-rw-r--r-- | toolkit/components/webextensions/LegacyExtensionsUtils.jsm | 250 |
1 files changed, 0 insertions, 250 deletions
diff --git a/toolkit/components/webextensions/LegacyExtensionsUtils.jsm b/toolkit/components/webextensions/LegacyExtensionsUtils.jsm deleted file mode 100644 index e8d276fe9..000000000 --- a/toolkit/components/webextensions/LegacyExtensionsUtils.jsm +++ /dev/null @@ -1,250 +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"; - -this.EXPORTED_SYMBOLS = ["LegacyExtensionsUtils"]; - -/* exported LegacyExtensionsUtils, LegacyExtensionContext */ - -/** - * This file exports helpers for Legacy Extensions that want to embed a webextensions - * and exchange messages with the embedded WebExtension. - */ - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Extension", - "resource://gre/modules/Extension.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Services", - "resource://gre/modules/Services.jsm"); - -Cu.import("resource://gre/modules/ExtensionChild.jsm"); -Cu.import("resource://gre/modules/ExtensionCommon.jsm"); - -var { - BaseContext, -} = ExtensionCommon; - -var { - Messenger, -} = ExtensionChild; - -/** - * Instances created from this class provide to a legacy extension - * a simple API to exchange messages with a webextension. - */ -var LegacyExtensionContext = class extends BaseContext { - /** - * Create a new LegacyExtensionContext given a target Extension instance. - * - * @param {Extension} targetExtension - * The webextension instance associated with this context. This will be the - * instance of the newly created embedded webextension when this class is - * used through the EmbeddedWebExtensionsUtils. - */ - constructor(targetExtension) { - super("legacy_extension", targetExtension); - - // Legacy Extensions (xul overlays, bootstrap restartless and Addon SDK) - // runs with a systemPrincipal. - let addonPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); - Object.defineProperty( - this, "principal", - {value: addonPrincipal, enumerable: true, configurable: true} - ); - - let cloneScope = Cu.Sandbox(this.principal, {}); - Cu.setSandboxMetadata(cloneScope, {addonId: targetExtension.id}); - Object.defineProperty( - this, "cloneScope", - {value: cloneScope, enumerable: true, configurable: true, writable: true} - ); - - let sender = {id: targetExtension.id}; - let filter = {extensionId: targetExtension.id}; - // Legacy addons live in the main process. Messages from other addons are - // Messages from WebExtensions are sent to the main process and forwarded via - // the parent process manager to the legacy extension. - this.messenger = new Messenger(this, [Services.cpmm], sender, filter); - - this.api = { - browser: { - runtime: { - onConnect: this.messenger.onConnect("runtime.onConnect"), - onMessage: this.messenger.onMessage("runtime.onMessage"), - }, - }, - }; - } - - /** - * This method is called when the extension shuts down or is unloaded, - * and it nukes the cloneScope sandbox, if any. - */ - unload() { - if (this.unloaded) { - throw new Error("Error trying to unload LegacyExtensionContext twice."); - } - super.unload(); - Cu.nukeSandbox(this.cloneScope); - this.cloneScope = null; - } -}; - -var EmbeddedExtensionManager; - -/** - * Instances of this class are used internally by the exported EmbeddedWebExtensionsUtils - * to manage the embedded webextension instance and the related LegacyExtensionContext - * instance used to exchange messages with it. - */ -class EmbeddedExtension { - /** - * Create a new EmbeddedExtension given the add-on id and the base resource URI of the - * container add-on (the webextension resources will be loaded from the "webextension/" - * subdir of the base resource URI for the legacy extension add-on). - * - * @param {Object} containerAddonParams - * An object with the following properties: - * @param {string} containerAddonParams.id - * The Add-on id of the Legacy Extension which will contain the embedded webextension. - * @param {nsIURI} containerAddonParams.resourceURI - * The nsIURI of the Legacy Extension container add-on. - */ - constructor({id, resourceURI}) { - this.addonId = id; - this.resourceURI = resourceURI; - - // Setup status flag. - this.started = false; - } - - /** - * Start the embedded webextension. - * - * @returns {Promise<LegacyContextAPI>} A promise which resolve to the API exposed to the - * legacy context. - */ - startup() { - if (this.started) { - return Promise.reject(new Error("This embedded extension has already been started")); - } - - // Setup the startup promise. - this.startupPromise = new Promise((resolve, reject) => { - let embeddedExtensionURI = Services.io.newURI("webextension/", null, this.resourceURI); - - // This is the instance of the WebExtension embedded in the hybrid add-on. - this.extension = new Extension({ - id: this.addonId, - resourceURI: embeddedExtensionURI, - }); - - // This callback is register to the "startup" event, emitted by the Extension instance - // after the extension manifest.json has been loaded without any errors, but before - // starting any of the defined contexts (which give the legacy part a chance to subscribe - // runtime.onMessage/onConnect listener before the background page has been loaded). - const onBeforeStarted = () => { - this.extension.off("startup", onBeforeStarted); - - // Resolve the startup promise and reset the startupError. - this.started = true; - this.startupPromise = null; - - // Create the legacy extension context, the legacy container addon - // needs to use it before the embedded webextension startup, - // because it is supposed to be used during the legacy container startup - // to subscribe its message listeners (which are supposed to be able to - // receive any message that the embedded part can try to send to it - // during its startup). - this.context = new LegacyExtensionContext(this.extension); - - // Destroy the LegacyExtensionContext cloneScope when - // the embedded webextensions is unloaded. - this.extension.callOnClose({ - close: () => { - this.context.unload(); - }, - }); - - // resolve startupPromise to execute any pending shutdown that has been - // chained to it. - resolve(this.context.api); - }; - - this.extension.on("startup", onBeforeStarted); - - // Run ambedded extension startup and catch any error during embedded extension - // startup. - this.extension.startup().catch((err) => { - this.started = false; - this.startupPromise = null; - this.extension.off("startup", onBeforeStarted); - - reject(err); - }); - }); - - return this.startupPromise; - } - - /** - * Shuts down the embedded webextension. - * - * @returns {Promise<void>} a promise that is resolved when the shutdown has been done - */ - shutdown() { - EmbeddedExtensionManager.untrackEmbeddedExtension(this); - - // If there is a pending startup, wait to be completed and then shutdown. - if (this.startupPromise) { - return this.startupPromise.then(() => { - this.extension.shutdown(); - }); - } - - // Run shutdown now if the embedded webextension has been correctly started - if (this.extension && this.started && !this.extension.hasShutdown) { - this.extension.shutdown(); - } - - return Promise.resolve(); - } -} - -// Keep track on the created EmbeddedExtension instances and destroy -// them when their container addon is going to be disabled or uninstalled. -EmbeddedExtensionManager = { - // Map of the existent EmbeddedExtensions instances by addon id. - embeddedExtensionsByAddonId: new Map(), - - untrackEmbeddedExtension(embeddedExtensionInstance) { - // Remove this instance from the tracked embedded extensions - let id = embeddedExtensionInstance.addonId; - if (this.embeddedExtensionsByAddonId.get(id) == embeddedExtensionInstance) { - this.embeddedExtensionsByAddonId.delete(id); - } - }, - - getEmbeddedExtensionFor({id, resourceURI}) { - let embeddedExtension = this.embeddedExtensionsByAddonId.get(id); - - if (!embeddedExtension) { - embeddedExtension = new EmbeddedExtension({id, resourceURI}); - // Keep track of the embedded extension instance. - this.embeddedExtensionsByAddonId.set(id, embeddedExtension); - } - - return embeddedExtension; - }, -}; - -this.LegacyExtensionsUtils = { - getEmbeddedExtensionFor: (addon) => { - return EmbeddedExtensionManager.getEmbeddedExtensionFor(addon); - }, -}; |