realms. this.#realms = new Map(); } initialize(sessionDataItems) { // Create the default realm, it is mapped to an empty string sandbox name. this.#realms.set("", this.#createRealm()); // This method, even though being async, is not awaited on purpose, // since for now the sessionDataItems are passed in response to an event in a for loop. this.#applyInitialSessionDataItems(sessionDataItems); // With the session data applied the handler is now ready to be used. this.emitEvent("window-global-handler-created", { contextId: this.contextId, innerWindowId: this.#innerWindowId, }); } destroy() { for (const realm of this.#realms.values()) { realm.destroy(); } this.emitEvent("windowglobal-pagehide", { context: this.context, innerWindowId: this.innerWindowId, }); this.#realms = null; super.destroy(); } /** * Returns the WindowGlobalMessageHandler module path. * * @returns {string} */ static get modulePath() { return "windowglobal"; } /** * Returns the WindowGlobalMessageHandler type. * * @returns {string} */ static get type() { return "WINDOW_GLOBAL"; } /** * For WINDOW_GLOBAL MessageHandlers, `context` is a BrowsingContext, * and BrowsingContext.id can be used as the context id. * * @param {BrowsingContext} context * WindowGlobalMessageHandler contexts are expected to be * BrowsingContexts. * @returns {string} * The browsing context id. */ static getIdFromContext(context) { return context.id; } get innerWindowId() { return this.#innerWindowId; } get realms() { return this.#realms; } get window() { return this.context.window; } #createRealm(sandboxName = null) { const realm = new lazy.WindowRealm(this.context.window, { sandboxName, }); this.emitEvent("realm-created", { realmInfo: realm.getInfo(), innerWindowId: this.innerWindowId, }); return realm; } #getRealmFromSandboxName(sandboxName = null) { if (sandboxName === null || sandboxName === "") { return this.#realms.get(""); } if (this.#realms.has(sandboxName)) { return this.#realms.get(sandboxName); } const realm = this.#createRealm(sandboxName); this.#realms.set(sandboxName, realm); return realm; } async #applyInitialSessionDataItems(sessionDataItems) { if (!Array.isArray(sessionDataItems)) { return; } const destination = { type: WindowGlobalMessageHandler.type, }; // Create a Map with the structure moduleName -> category -> relevant session data items. const structuredUpdates = new Map(); for (const sessionDataItem of sessionDataItems) { const { category, contextDescriptor, moduleName } = sessionDataItem; if (!this.matchesContext(contextDescriptor)) { continue; } if (!structuredUpdates.has(moduleName)) { // Skip session data item if the module is not present // for the destination. if (!this.moduleCache.hasModuleClass(moduleName, destination)) { continue; } structuredUpdates.set(moduleName, new Map()); } if (!structuredUpdates.get(moduleName).has(category)) { structuredUpdates.get(moduleName).set(category, new Set()); } structuredUpdates.get(moduleName).get(category).add(sessionDataItem); } const sessionDataPromises = []; for (const [moduleName, categories] of structuredUpdates.entries()) { for (const [category, relevantSessionData] of categories.entries()) { sessionDataPromises.push( this.handleCommand({ moduleName, commandName: "_applySessionData", params: { category, sessionData: Array.from(relevantSessionData), initial: true, }, destination, }) ); } } await Promise.all(sessionDataPromises); } forwardCommand(command) { switch (command.destination.type) { case lazy.RootMessageHandler.type: return lazy .getMessageHandlerFrameChildActor(this) .sendCommand(command, this.sessionId); default: throw new Error( `Cannot forward command to "${command.destination.type}" from "${this.constructor.type}".` ); } } /** * If realmId is null or not provided get the realm for * a given sandboxName, otherwise find the realm * in the cache with the realm id equal given realmId. * * @param {object} options * @param {string|null=} options.realmId * The realm id. * @param {string=} options.sandboxName * The name of sandbox * * @returns {Realm} * The realm object. */ getRealm(options = {}) { const { realmId = null, sandboxName } = options; if (realmId === null) { return this.#getRealmFromSandboxName(sandboxName); } const realm = Array.from(this.#realms.values()).find( realm => realm.id === realmId ); if (realm) { return realm; } throw new lazy.error.NoSuchFrameError(`Realm with id ${realmId} not found`); } /** * Check if the context matches a provided context descriptor. * * @param {object} contextDescriptor * A context descriptor. * @returns {boolean} * Return true if the context matches a provided context descriptor, * false otherwise. */ matchesContext(contextDescriptor) { return this.contextMatchesDescriptor(this.context, contextDescriptor); } /** * Send a command to the root MessageHandler. * * @param {Command} command * The command to send to the root MessageHandler. * @returns {Promise} * A promise which resolves with the return value of the command. */ sendRootCommand(command) { return this.handleCommand({ ...command, destination: { type: lazy.RootMessageHandler.type, }, }); } } PK