"use strict"; import { Message } from "../messaging"; import { BridgeInfo } from "../lib/bridge"; import { TypedMessagePort } from "../lib/TypedMessagePort"; import CastSDK from "./sdk"; import { PageEventMessenger, ExtensionEventMessenger } from "./eventMessaging"; // Create messengers manually instead of relying on getters const eventMessaging = { page: new PageEventMessenger(), extension: new ExtensionEventMessenger() }; let initializedBridgeInfo: BridgeInfo; let initializedBackgroundPort: MessagePort; /** * To support exporting an API from a module, we need to * retain the event-based message passing despite not * actually crossing any context boundaries. The cast instance * listens for and emits these messages, and changing that * behavior is too messy. */ export function ensureInit(): Promise> { return new Promise(async (resolve, reject) => { // If already initialized, just return existing bridge info if (initializedBridgeInfo) { if (initializedBridgeInfo.isVersionCompatible) { resolve(initializedBackgroundPort); } else { reject(); } return; } const channel = new MessageChannel(); initializedBackgroundPort = channel.port1; /** * If the module is imported into a background script * context, the location will be the internal extension URL, * whereas in a content script, it will be the content page * URL. */ if (window.location.protocol === "moz-extension:") { const { default: castManager } = await import( "../background/castManager" ); // port2 will post bridge messages to port 1 await castManager.init(); await castManager.createInstance(channel.port2); // bridge -> cast instance channel.port1.onmessage = ev => { const message = ev.data as Message; // Send message to cast instance eventMessaging.extension.sendMessage(message); handleIncomingMessageToCast(message); }; // cast instance -> bridge eventMessaging.extension.addListener(message => channel.port1.postMessage(message) ); } else { /** * Import reference to message port created by contentBridge. * Creation of the port triggers side-effects in the * background script. */ const { backgroundPort } = await import("./contentBridge"); // backgroundPort -> channel.port2 backgroundPort.onMessage.addListener((message: Message) => { channel.port2.postMessage(message); }); // channel.port2 -> backgroundPort channel.port2.onmessage = ev => { const message = ev.data as Message; backgroundPort.postMessage(message); }; // Handle cast messages eventMessaging.page.addListener(message => handleIncomingMessageToCast(message) ); } function handleIncomingMessageToCast(message: Message) { switch (message.subject) { case "cast:initialized": { initializedBridgeInfo = message.data; if (initializedBridgeInfo.isVersionCompatible) { resolve(initializedBackgroundPort); } else { reject(); } } } } }); } export default new CastSDK();