mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Move some background modules to a separate folder and fix init order
This commit is contained in:
237
ext/src/background/ShimManager.ts
Normal file
237
ext/src/background/ShimManager.ts
Normal file
@@ -0,0 +1,237 @@
|
||||
"use strict";
|
||||
|
||||
import bridge from "../lib/bridge";
|
||||
import loadSender from "../lib/loadSender";
|
||||
import options from "../lib/options";
|
||||
|
||||
import { TypedEventTarget } from "../lib/typedEvents";
|
||||
import { Message } from "../types";
|
||||
|
||||
import { ReceiverSelectorMediaType } from "./receiverSelector";
|
||||
|
||||
import ReceiverSelectorManager
|
||||
from "./receiverSelector/ReceiverSelectorManager";
|
||||
|
||||
import StatusManager from "./StatusManager";
|
||||
|
||||
|
||||
type Port = browser.runtime.Port | MessagePort;
|
||||
|
||||
export interface Shim {
|
||||
bridgePort: browser.runtime.Port;
|
||||
contentPort: Port;
|
||||
contentTabId?: number;
|
||||
contentFrameId?: number;
|
||||
}
|
||||
|
||||
|
||||
// tslint:disable-next-line:new-parens
|
||||
export default new class ShimManager {
|
||||
private activeShims = new Set<Shim>();
|
||||
|
||||
public async init () {
|
||||
await StatusManager.init();
|
||||
await this.initStatusListeners();
|
||||
}
|
||||
|
||||
public async createShim (port: Port) {
|
||||
const shim = await (port instanceof MessagePort
|
||||
? this.createShimFromBackground(port)
|
||||
: this.createShimFromContent(port));
|
||||
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/initialized"
|
||||
, data: await bridge.getInfo()
|
||||
});
|
||||
|
||||
this.activeShims.add(shim);
|
||||
}
|
||||
|
||||
private async createShimFromBackground (
|
||||
contentPort: MessagePort): Promise<Shim> {
|
||||
|
||||
const shim: Shim = {
|
||||
bridgePort: await bridge.connect()
|
||||
, contentPort
|
||||
};
|
||||
|
||||
shim.bridgePort.onDisconnect.addListener(() => {
|
||||
contentPort.close();
|
||||
this.activeShims.delete(shim);
|
||||
});
|
||||
|
||||
shim.bridgePort.onMessage.addListener((message: Message) => {
|
||||
contentPort.postMessage(message);
|
||||
});
|
||||
|
||||
contentPort.onmessage = ev => {
|
||||
const message = ev.data as Message;
|
||||
this.handleContentMessage(shim, message);
|
||||
};
|
||||
|
||||
return shim;
|
||||
}
|
||||
|
||||
private async createShimFromContent (
|
||||
contentPort: browser.runtime.Port): Promise<Shim> {
|
||||
|
||||
/**
|
||||
* If there's already an active shim for the sender
|
||||
* tab/frame ID, disconnect it.
|
||||
*/
|
||||
for (const activeShim of this.activeShims) {
|
||||
if (activeShim.contentTabId === contentPort.sender.tab.id
|
||||
&& activeShim.contentFrameId === contentPort.sender.frameId) {
|
||||
activeShim.bridgePort.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
const shim: Shim = {
|
||||
bridgePort: await bridge.connect()
|
||||
, contentPort
|
||||
, contentTabId: contentPort.sender.tab.id
|
||||
, contentFrameId: contentPort.sender.frameId
|
||||
};
|
||||
|
||||
|
||||
const onContentPortMessage = (message: Message) => {
|
||||
this.handleContentMessage(shim, message);
|
||||
};
|
||||
|
||||
const onBridgePortMessage = (message: Message) => {
|
||||
contentPort.postMessage(message);
|
||||
};
|
||||
|
||||
const onDisconnect = () => {
|
||||
shim.bridgePort.onMessage.removeListener(onBridgePortMessage);
|
||||
contentPort.onMessage.removeListener(onContentPortMessage);
|
||||
|
||||
shim.bridgePort.disconnect();
|
||||
contentPort.disconnect();
|
||||
|
||||
this.activeShims.delete(shim);
|
||||
};
|
||||
|
||||
|
||||
shim.bridgePort.onDisconnect.addListener(onDisconnect);
|
||||
shim.bridgePort.onMessage.addListener(onBridgePortMessage);
|
||||
|
||||
contentPort.onDisconnect.addListener(onDisconnect);
|
||||
contentPort.onMessage.addListener(onContentPortMessage);
|
||||
|
||||
return shim;
|
||||
}
|
||||
|
||||
private async handleContentMessage (shim: Shim, message: Message) {
|
||||
const [ destination ] = message.subject.split(":/");
|
||||
if (destination === "bridge") {
|
||||
shim.bridgePort.postMessage(message);
|
||||
}
|
||||
|
||||
switch (message.subject) {
|
||||
case "main:/shimInitialized": {
|
||||
for (const receiver of StatusManager.getReceivers()) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/serviceUp"
|
||||
, data: { id: receiver.id }
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "main:/selectReceiverBegin": {
|
||||
const allMediaTypes =
|
||||
ReceiverSelectorMediaType.App
|
||||
| ReceiverSelectorMediaType.Tab
|
||||
| ReceiverSelectorMediaType.Screen
|
||||
| ReceiverSelectorMediaType.File;
|
||||
|
||||
try {
|
||||
const selection = await ReceiverSelectorManager
|
||||
.getSelection(
|
||||
ReceiverSelectorMediaType.App
|
||||
, allMediaTypes);
|
||||
|
||||
// Handle cancellation
|
||||
if (!selection) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverCancelled"
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the media type returned from the selector has been
|
||||
* changed, we need to cancel the current sender and switch
|
||||
* it out for the right one.
|
||||
*/
|
||||
if (selection.mediaType !== ReceiverSelectorMediaType.App) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverCancelled"
|
||||
});
|
||||
|
||||
loadSender({
|
||||
tabId: shim.contentTabId
|
||||
, frameId: shim.contentFrameId
|
||||
, selection
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Pass selection back to shim
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverEnd"
|
||||
, data: selection
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
// TODO: Report errors properly
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverCancelled"
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: If we're closing a selector, make sure it's the
|
||||
* same one that caused the session creation.
|
||||
*/
|
||||
case "main:/sessionCreated": {
|
||||
const selector = await ReceiverSelectorManager.getSelector();
|
||||
const shouldClose = await options.get(
|
||||
"receiverSelectorWaitForConnection");
|
||||
|
||||
if (selector.isOpen && shouldClose) {
|
||||
selector.close();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async initStatusListeners () {
|
||||
StatusManager.addEventListener("serviceUp", ev => {
|
||||
for (const shim of this.activeShims) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/serviceUp"
|
||||
, data: { id: ev.detail.id }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
StatusManager.addEventListener("serviceDown", ev => {
|
||||
for (const shim of this.activeShims) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/serviceDown"
|
||||
, data: { id: ev.detail.id }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
import bridge from "./lib/bridge";
|
||||
import options from "./lib/options";
|
||||
import bridge from "../lib/bridge";
|
||||
import options from "../lib/options";
|
||||
|
||||
import { TypedEventTarget } from "./lib/typedEvents";
|
||||
import { Message, Receiver, ReceiverStatus } from "./types";
|
||||
import { TypedEventTarget } from "../lib/typedEvents";
|
||||
import { Message, Receiver, ReceiverStatus } from "../types";
|
||||
|
||||
|
||||
interface ReceiverStatusMessage extends Message {
|
||||
@@ -36,7 +36,9 @@ interface EventMap {
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:new-parens
|
||||
export default new class extends TypedEventTarget<EventMap> {
|
||||
export default new class StatusManager
|
||||
extends TypedEventTarget<EventMap> {
|
||||
|
||||
private bridgePort: browser.runtime.Port;
|
||||
private receivers = new Map<string, Receiver>();
|
||||
|
||||
@@ -46,25 +48,31 @@ export default new class extends TypedEventTarget<EventMap> {
|
||||
// Bind listeners
|
||||
this.onBridgePortMessage = this.onBridgePortMessage.bind(this);
|
||||
this.onBridgePortDisconnect = this.onBridgePortDisconnect.bind(this);
|
||||
}
|
||||
|
||||
this.initBridgePort();
|
||||
public async init () {
|
||||
if (!this.bridgePort) {
|
||||
await this.createBridgePort();
|
||||
}
|
||||
}
|
||||
|
||||
public getReceivers () {
|
||||
return Array.from(this.receivers.values());
|
||||
}
|
||||
|
||||
private async initBridgePort () {
|
||||
this.bridgePort = await bridge.connect();
|
||||
this.bridgePort.onMessage.addListener(this.onBridgePortMessage);
|
||||
this.bridgePort.onDisconnect.addListener(this.onBridgePortDisconnect);
|
||||
private async createBridgePort () {
|
||||
const bridgePort = await bridge.connect();
|
||||
bridgePort.onMessage.addListener(this.onBridgePortMessage);
|
||||
bridgePort.onDisconnect.addListener(this.onBridgePortDisconnect);
|
||||
|
||||
this.bridgePort.postMessage({
|
||||
bridgePort.postMessage({
|
||||
subject: "bridge:/initialize"
|
||||
, data: {
|
||||
shouldWatchStatus: true
|
||||
}
|
||||
});
|
||||
|
||||
return bridgePort;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +156,7 @@ export default new class extends TypedEventTarget<EventMap> {
|
||||
this.bridgePort = null;
|
||||
|
||||
window.setTimeout(async () => {
|
||||
this.initBridgePort();
|
||||
this.bridgePort = await this.createBridgePort();
|
||||
}, 10000);
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import options from "./lib/options";
|
||||
import { TypedEventTarget } from "./lib/typedEvents";
|
||||
import options from "../lib/options";
|
||||
import { TypedEventTarget } from "../lib/typedEvents";
|
||||
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
@@ -1,17 +1,17 @@
|
||||
"use strict";
|
||||
|
||||
import bridge from "../lib/bridge";
|
||||
import options from "../lib/options";
|
||||
import bridge from "../../lib/bridge";
|
||||
import options from "../../lib/options";
|
||||
|
||||
import { TypedEventTarget } from "../../lib/typedEvents";
|
||||
import { getWindowCenteredProps } from "../../lib/utils";
|
||||
import { Message, Receiver } from "../../types";
|
||||
|
||||
import ReceiverSelector, {
|
||||
ReceiverSelection
|
||||
, ReceiverSelectorEvents
|
||||
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
||||
|
||||
import { TypedEventTarget } from "../lib/typedEvents";
|
||||
import { getWindowCenteredProps } from "../lib/utils";
|
||||
import { Message, Receiver } from "../types";
|
||||
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
@@ -33,7 +33,7 @@ interface NativeReceiverSelectorErrorMessage extends Message {
|
||||
|
||||
|
||||
// TODO: Figure out lifetime properly
|
||||
export default class NativeMacReceiverSelector
|
||||
export default class NativeReceiverSelector
|
||||
extends TypedEventTarget<ReceiverSelectorEvents>
|
||||
implements ReceiverSelector {
|
||||
|
||||
@@ -4,11 +4,11 @@ import ReceiverSelector, {
|
||||
ReceiverSelectorEvents
|
||||
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
||||
|
||||
import options from "../lib/options";
|
||||
import options from "../../lib/options";
|
||||
|
||||
import { TypedEventTarget } from "../lib/typedEvents";
|
||||
import { getWindowCenteredProps } from "../lib/utils";
|
||||
import { Message, Receiver } from "../types";
|
||||
import { TypedEventTarget } from "../../lib/typedEvents";
|
||||
import { getWindowCenteredProps } from "../../lib/utils";
|
||||
import { Message, Receiver } from "../../types";
|
||||
|
||||
|
||||
export default class PopupReceiverSelector
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import { TypedEventTarget } from "../lib/typedEvents";
|
||||
import { Receiver } from "../types";
|
||||
import { TypedEventTarget } from "../../lib/typedEvents";
|
||||
import { Receiver } from "../../types";
|
||||
|
||||
|
||||
export enum ReceiverSelectorMediaType {
|
||||
@@ -1,31 +1,43 @@
|
||||
"use strict";
|
||||
|
||||
import options from "./lib/options";
|
||||
import options from "../../lib/options";
|
||||
|
||||
import { getReceiverSelector
|
||||
, ReceiverSelection
|
||||
, ReceiverSelector
|
||||
, ReceiverSelectorMediaType
|
||||
, ReceiverSelectorType } from "./receiver_selectors";
|
||||
import StatusManager from "../StatusManager";
|
||||
|
||||
import StatusManager from "./StatusManager";
|
||||
import { ReceiverSelector
|
||||
, ReceiverSelectorType } from "./";
|
||||
import { ReceiverSelection
|
||||
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
||||
|
||||
import NativeReceiverSelector from "./NativeReceiverSelector";
|
||||
import PopupReceiverSelector from "./PopupReceiverSelector";
|
||||
|
||||
|
||||
async function createSelector () {
|
||||
const type = await options.get("receiverSelectorType");
|
||||
|
||||
switch (type) {
|
||||
case ReceiverSelectorType.Native: {
|
||||
return new NativeReceiverSelector();
|
||||
}
|
||||
case ReceiverSelectorType.Popup: {
|
||||
return new PopupReceiverSelector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let sharedSelector: ReceiverSelector;
|
||||
|
||||
async function getSelector () {
|
||||
return getReceiverSelector(
|
||||
await options.get("receiverSelectorType"));
|
||||
}
|
||||
|
||||
async function getSharedSelector () {
|
||||
if (!sharedSelector) {
|
||||
sharedSelector = await getSelector();
|
||||
sharedSelector = await createSelector();
|
||||
}
|
||||
|
||||
return sharedSelector;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens a receiver selector with the specified
|
||||
* default/available media types.
|
||||
@@ -46,16 +58,14 @@ async function getSelection (
|
||||
: Promise<ReceiverSelection> {
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
/**
|
||||
* Close any existing selector, and renew to minimize issues
|
||||
* with bridge failing.
|
||||
*/
|
||||
await getSharedSelector();
|
||||
if (sharedSelector.isOpen) {
|
||||
|
||||
// Close an existing open selector
|
||||
if (sharedSelector && sharedSelector.isOpen) {
|
||||
sharedSelector.close();
|
||||
}
|
||||
|
||||
sharedSelector = await getSelector();
|
||||
// Get a new selector for each selection
|
||||
sharedSelector = await createSelector();
|
||||
|
||||
sharedSelector.addEventListener("selected", ev => {
|
||||
console.info("fx_cast (Debug): Selected receiver", ev.detail);
|
||||
@@ -72,6 +82,10 @@ async function getSelection (
|
||||
reject();
|
||||
});
|
||||
|
||||
|
||||
// Ensure status manager is initialized
|
||||
await StatusManager.init();
|
||||
|
||||
sharedSelector.open(
|
||||
StatusManager.getReceivers()
|
||||
, defaultMediaType
|
||||
@@ -81,5 +95,5 @@ async function getSelection (
|
||||
|
||||
export default {
|
||||
getSelection
|
||||
, getSharedSelector
|
||||
, getSelector
|
||||
};
|
||||
17
ext/src/background/receiverSelector/index.ts
Normal file
17
ext/src/background/receiverSelector/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
|
||||
import NativeReceiverSelector from "./NativeReceiverSelector";
|
||||
import PopupReceiverSelector from "./PopupReceiverSelector";
|
||||
|
||||
|
||||
export type ReceiverSelector =
|
||||
NativeReceiverSelector
|
||||
| PopupReceiverSelector;
|
||||
|
||||
export enum ReceiverSelectorType {
|
||||
Popup
|
||||
, Native
|
||||
}
|
||||
|
||||
export { ReceiverSelection
|
||||
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
||||
@@ -1,230 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import bridge from "./lib/bridge";
|
||||
import loadSender from "./lib/loadSender";
|
||||
import options from "./lib/options";
|
||||
|
||||
import { TypedEventTarget } from "./lib/typedEvents";
|
||||
import { Message } from "./types";
|
||||
|
||||
import { ReceiverSelectorMediaType } from "./receiver_selectors";
|
||||
|
||||
import SelectorManager from "./SelectorManager";
|
||||
import StatusManager from "./StatusManager";
|
||||
|
||||
|
||||
type Port = browser.runtime.Port | MessagePort;
|
||||
|
||||
export interface Shim {
|
||||
bridgePort: browser.runtime.Port;
|
||||
contentPort: Port;
|
||||
contentTabId?: number;
|
||||
contentFrameId?: number;
|
||||
}
|
||||
|
||||
|
||||
const activeShims = new Set<Shim>();
|
||||
|
||||
StatusManager.addEventListener("serviceUp", ev => {
|
||||
for (const shim of activeShims) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/serviceUp"
|
||||
, data: { id: ev.detail.id }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
StatusManager.addEventListener("serviceDown", ev => {
|
||||
for (const shim of activeShims) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/serviceDown"
|
||||
, data: { id: ev.detail.id }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
async function createShim (port: Port): Promise<void> {
|
||||
const shim = await (port instanceof MessagePort
|
||||
? createShimFromBackground(port)
|
||||
: createShimFromContent(port));
|
||||
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/initialized"
|
||||
, data: await bridge.getInfo()
|
||||
});
|
||||
|
||||
activeShims.add(shim);
|
||||
}
|
||||
|
||||
|
||||
async function createShimFromBackground (
|
||||
contentPort: MessagePort): Promise<Shim> {
|
||||
|
||||
const shim: Shim = {
|
||||
bridgePort: await bridge.connect()
|
||||
, contentPort
|
||||
};
|
||||
|
||||
shim.bridgePort.onDisconnect.addListener(() => {
|
||||
contentPort.close();
|
||||
activeShims.delete(shim);
|
||||
});
|
||||
|
||||
shim.bridgePort.onMessage.addListener((message: Message) => {
|
||||
contentPort.postMessage(message);
|
||||
});
|
||||
|
||||
contentPort.onmessage = ev => {
|
||||
const message = ev.data as Message;
|
||||
handleContentMessage(shim, message);
|
||||
};
|
||||
|
||||
return shim;
|
||||
}
|
||||
|
||||
|
||||
async function createShimFromContent (
|
||||
contentPort: browser.runtime.Port): Promise<Shim> {
|
||||
|
||||
/**
|
||||
* If there's already an active shim for the sender
|
||||
* tab/frame ID, disconnect it.
|
||||
*/
|
||||
for (const activeShim of activeShims) {
|
||||
if (activeShim.contentTabId === contentPort.sender.tab.id
|
||||
&& activeShim.contentFrameId === contentPort.sender.frameId) {
|
||||
activeShim.bridgePort.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
const shim: Shim = {
|
||||
bridgePort: await bridge.connect()
|
||||
, contentPort
|
||||
, contentTabId: contentPort.sender.tab.id
|
||||
, contentFrameId: contentPort.sender.frameId
|
||||
};
|
||||
|
||||
function onContentPortMessage (message: Message) {
|
||||
handleContentMessage(shim, message);
|
||||
}
|
||||
function onBridgePortMessage (message: Message) {
|
||||
contentPort.postMessage(message);
|
||||
}
|
||||
|
||||
function onDisconnect () {
|
||||
shim.bridgePort.onMessage.removeListener(onBridgePortMessage);
|
||||
contentPort.onMessage.removeListener(onContentPortMessage);
|
||||
|
||||
shim.bridgePort.disconnect();
|
||||
contentPort.disconnect();
|
||||
|
||||
activeShims.delete(shim);
|
||||
}
|
||||
|
||||
|
||||
shim.bridgePort.onDisconnect.addListener(onDisconnect);
|
||||
shim.bridgePort.onMessage.addListener(onBridgePortMessage);
|
||||
|
||||
contentPort.onDisconnect.addListener(onDisconnect);
|
||||
contentPort.onMessage.addListener(onContentPortMessage);
|
||||
|
||||
|
||||
return shim;
|
||||
}
|
||||
|
||||
|
||||
async function handleContentMessage (shim: Shim, message: Message) {
|
||||
const [ destination ] = message.subject.split(":/");
|
||||
if (destination === "bridge") {
|
||||
shim.bridgePort.postMessage(message);
|
||||
}
|
||||
|
||||
switch (message.subject) {
|
||||
case "main:/shimInitialized": {
|
||||
for (const receiver of StatusManager.getReceivers()) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/serviceUp"
|
||||
, data: { id: receiver.id }
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "main:/selectReceiverBegin": {
|
||||
const allMediaTypes =
|
||||
ReceiverSelectorMediaType.App
|
||||
| ReceiverSelectorMediaType.Tab
|
||||
| ReceiverSelectorMediaType.Screen
|
||||
| ReceiverSelectorMediaType.File;
|
||||
|
||||
try {
|
||||
const selection = await SelectorManager.getSelection(
|
||||
ReceiverSelectorMediaType.App
|
||||
, allMediaTypes);
|
||||
|
||||
// Handle cancellation
|
||||
if (!selection) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverCancelled"
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the media type returned from the selector has been
|
||||
* changed, we need to cancel the current sender and switch
|
||||
* it out for the right one.
|
||||
*/
|
||||
if (selection.mediaType !== ReceiverSelectorMediaType.App) {
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverCancelled"
|
||||
});
|
||||
|
||||
loadSender({
|
||||
tabId: shim.contentTabId
|
||||
, frameId: shim.contentFrameId
|
||||
, selection
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Pass selection back to shim
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverEnd"
|
||||
, data: selection
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
// TODO: Report errors properly
|
||||
shim.contentPort.postMessage({
|
||||
subject: "shim:/selectReceiverCancelled"
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: If we're closing a selector, make sure it's the
|
||||
* same one that caused the session creation.
|
||||
*/
|
||||
case "main:/sessionCreated": {
|
||||
const selector = await SelectorManager.getSharedSelector();
|
||||
|
||||
const shouldClose = await options.get(
|
||||
"receiverSelectorWaitForConnection");
|
||||
|
||||
if (selector.isOpen && shouldClose) {
|
||||
selector.close();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default createShim;
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import { ReceiverSelectorType } from "./background/receiverSelector";
|
||||
import { Options } from "./lib/options";
|
||||
import { ReceiverSelectorType } from "./receiver_selectors";
|
||||
|
||||
|
||||
export default {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { stringify } from "./utils";
|
||||
|
||||
import { ReceiverSelection
|
||||
, ReceiverSelectorMediaType } from "../receiver_selectors";
|
||||
, ReceiverSelectorMediaType } from "../background/receiverSelector";
|
||||
|
||||
|
||||
interface LoadSenderOptions {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Message } from "../types";
|
||||
const WEBSOCKET_DAEMON_URL = "ws://localhost:9556";
|
||||
|
||||
|
||||
type DisconnectListener = (port: browser.runtime.Port) => void;;
|
||||
type DisconnectListener = (port: browser.runtime.Port) => void;
|
||||
type MessageListener = (message: any) => void;
|
||||
|
||||
function connectNative (application: string) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import defaultOptions from "../defaultOptions";
|
||||
|
||||
import { ReceiverSelectorType } from "../receiver_selectors/";
|
||||
import { ReceiverSelectorType } from "../background/receiverSelector";
|
||||
import { Message } from "../types";
|
||||
import { TypedEventTarget } from "./typedEvents";
|
||||
|
||||
@@ -16,13 +16,13 @@ export interface Options {
|
||||
localMediaServerPort: number;
|
||||
mirroringEnabled: boolean;
|
||||
mirroringAppId: string;
|
||||
receiverSelectorType: ReceiverSelectorType.Popup;
|
||||
receiverSelectorType: ReceiverSelectorType;
|
||||
receiverSelectorCloseIfFocusLost: boolean;
|
||||
receiverSelectorWaitForConnection: boolean;
|
||||
userAgentWhitelistEnabled: boolean;
|
||||
userAgentWhitelist: string[];
|
||||
|
||||
[key: string]: Options[keyof Options]
|
||||
[key: string]: Options[keyof Options];
|
||||
}
|
||||
|
||||
|
||||
@@ -49,28 +49,30 @@ export default new class extends TypedEventTarget<EventMap> {
|
||||
const { oldValue, newValue } = _changes.options;
|
||||
const changedKeys = [];
|
||||
|
||||
for (const key in newValue) {
|
||||
// Don't track added keys
|
||||
if (!(key in oldValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const oldKeyValue = oldValue[key];
|
||||
const newKeyValue = newValue[key];
|
||||
|
||||
// Equality comparison
|
||||
if (oldKeyValue === newKeyValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Array comparison
|
||||
if (oldKeyValue instanceof Array
|
||||
&& newKeyValue instanceof Array) {
|
||||
if (oldKeyValue.length === newKeyValue.length
|
||||
&& oldKeyValue.every((value, index) =>
|
||||
value === newKeyValue[index])) {
|
||||
for (const key of Object.keys(newValue)) {
|
||||
if (oldValue) {
|
||||
// Don't track added keys
|
||||
if (!(key in oldValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const oldKeyValue = oldValue[key];
|
||||
const newKeyValue = newValue[key];
|
||||
|
||||
// Equality comparison
|
||||
if (oldKeyValue === newKeyValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Array comparison
|
||||
if (oldKeyValue instanceof Array
|
||||
&& newKeyValue instanceof Array) {
|
||||
if (oldKeyValue.length === newKeyValue.length
|
||||
&& oldKeyValue.every((value, index) =>
|
||||
value === newKeyValue[index])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changedKeys.push(key);
|
||||
|
||||
@@ -8,20 +8,19 @@ import options, { Options } from "./lib/options";
|
||||
import { getChromeUserAgent } from "./lib/userAgents";
|
||||
import { stringify } from "./lib/utils";
|
||||
|
||||
import { ReceiverSelection
|
||||
, ReceiverSelectorMediaType } from "./receiver_selectors";
|
||||
|
||||
import { Message } from "./types";
|
||||
|
||||
import { CAST_FRAMEWORK_LOADER_SCRIPT_URL
|
||||
, CAST_LOADER_SCRIPT_URL } from "./lib/endpoints";
|
||||
|
||||
import { ReceiverSelection
|
||||
, ReceiverSelectorMediaType } from "./background/receiverSelector";
|
||||
|
||||
import SelectorManager from "./SelectorManager";
|
||||
import StatusManager from "./StatusManager";
|
||||
import ReceiverSelectorManager
|
||||
from "./background/receiverSelector/ReceiverSelectorManager";
|
||||
|
||||
import createMenus from "./createMenus";
|
||||
import createShim, { Shim } from "./createShim";
|
||||
import createMenus from "./background/createMenus";
|
||||
import ShimManager from "./background/ShimManager";
|
||||
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
@@ -48,33 +47,6 @@ browser.runtime.onInstalled.addListener(async details => {
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* When a message port connection with the name "shim" is
|
||||
* established, pass it to createShim to handle the setup
|
||||
* and maintenance.
|
||||
*/
|
||||
browser.runtime.onConnect.addListener(async port => {
|
||||
if (port.name === "shim") {
|
||||
createShim(port);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* When the browser action is clicked, open a receiver
|
||||
* selector and load a sender for the response. The
|
||||
* mirroring sender is loaded into the current tab at the
|
||||
* top-level frame.
|
||||
*/
|
||||
browser.browserAction.onClicked.addListener(async tab => {
|
||||
const selection = await SelectorManager.getSelection();
|
||||
|
||||
loadSender({
|
||||
tabId: tab.id
|
||||
, frameId: 0
|
||||
, selection
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
async function initMenus () {
|
||||
console.info("fx_cast (Debug): init (menus)");
|
||||
@@ -93,7 +65,7 @@ async function initMenus () {
|
||||
| ReceiverSelectorMediaType.Screen
|
||||
| ReceiverSelectorMediaType.File;
|
||||
|
||||
const selection = await SelectorManager.getSelection(
|
||||
const selection = await ReceiverSelectorManager.getSelection(
|
||||
ReceiverSelectorMediaType.App
|
||||
, allMediaTypes);
|
||||
|
||||
@@ -134,7 +106,7 @@ async function initMenus () {
|
||||
}
|
||||
|
||||
case menuIdMirroringCast: {
|
||||
const selection = await SelectorManager.getSelection();
|
||||
const selection = await ReceiverSelectorManager.getSelection();
|
||||
|
||||
loadSender({
|
||||
tabId: tab.id
|
||||
@@ -268,8 +240,13 @@ function initWhitelist () {
|
||||
}
|
||||
|
||||
|
||||
let isInitialized = false;
|
||||
|
||||
async function init () {
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* If options haven't been set yet, we can't properly
|
||||
* initialize, so wait until init is called again in the
|
||||
@@ -281,10 +258,42 @@ async function init () {
|
||||
|
||||
console.info("fx_cast (Debug): init");
|
||||
|
||||
isInitialized = true;
|
||||
|
||||
initMenus();
|
||||
initRequestListener();
|
||||
initWhitelist();
|
||||
|
||||
await initMenus();
|
||||
await initRequestListener();
|
||||
await initWhitelist();
|
||||
|
||||
await ShimManager.init();
|
||||
|
||||
|
||||
/**
|
||||
* When a message port connection with the name "shim" is
|
||||
* established, pass it to createShim to handle the setup
|
||||
* and maintenance.
|
||||
*/
|
||||
browser.runtime.onConnect.addListener(async port => {
|
||||
if (port.name === "shim") {
|
||||
ShimManager.createShim(port);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* When the browser action is clicked, open a receiver
|
||||
* selector and load a sender for the response. The
|
||||
* mirroring sender is loaded into the current tab at the
|
||||
* top-level frame.
|
||||
*/
|
||||
browser.browserAction.onClicked.addListener(async tab => {
|
||||
const selection = await ReceiverSelectorManager.getSelection();
|
||||
|
||||
loadSender({
|
||||
tabId: tab.id
|
||||
, frameId: 0
|
||||
, selection
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import NativeMacReceiverSelector
|
||||
from "./NativeMacReceiverSelector";
|
||||
import PopupReceiverSelector
|
||||
from "./PopupReceiverSelector";
|
||||
|
||||
|
||||
import { ReceiverSelection
|
||||
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
||||
|
||||
type ReceiverSelector = ReturnType<typeof getReceiverSelector>;
|
||||
|
||||
export {
|
||||
ReceiverSelector
|
||||
, ReceiverSelection
|
||||
, ReceiverSelectorMediaType
|
||||
};
|
||||
|
||||
export enum ReceiverSelectorType {
|
||||
Popup
|
||||
, NativeMac
|
||||
}
|
||||
|
||||
export function getReceiverSelector (type: ReceiverSelectorType) {
|
||||
switch (type) {
|
||||
case ReceiverSelectorType.Popup: {
|
||||
return new PopupReceiverSelector();
|
||||
}
|
||||
case ReceiverSelectorType.NativeMac: {
|
||||
return new NativeMacReceiverSelector();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@
|
||||
import options from "../lib/options";
|
||||
import cast, { ensureInit } from "../shim/export";
|
||||
|
||||
import { ReceiverSelectorMediaType }
|
||||
from "../receiver_selectors/ReceiverSelector";
|
||||
|
||||
import { ReceiverSelectorMediaType } from "../background/receiverSelector";
|
||||
import { Receiver } from "../types";
|
||||
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@ import { AutoJoinPolicy
|
||||
import * as media from "./media";
|
||||
|
||||
|
||||
import { ReceiverSelectorMediaType }
|
||||
from "../../receiver_selectors/ReceiverSelector";
|
||||
import { ReceiverSelectorMediaType } from "../../background/receiverSelector";
|
||||
import { Receiver } from "../../types";
|
||||
import { onMessage, sendMessageResponse } from "../eventMessageChannel";
|
||||
|
||||
|
||||
@@ -5,7 +5,11 @@ import * as cast from "./cast";
|
||||
import { BridgeInfo } from "../lib/bridge";
|
||||
import { Message } from "../types";
|
||||
|
||||
import { onMessage, onMessageResponse, sendMessage } from "./eventMessageChannel";
|
||||
import { onMessage
|
||||
, onMessageResponse
|
||||
, sendMessage } from "./eventMessageChannel";
|
||||
|
||||
import ShimManager from "../background/ShimManager";
|
||||
|
||||
|
||||
let initializedBridgeInfo: BridgeInfo;
|
||||
@@ -42,10 +46,9 @@ export function ensureInit (): Promise<MessagePort> {
|
||||
* URL.
|
||||
*/
|
||||
if (window.location.protocol === "moz-extension:") {
|
||||
const { default: createShim } = await import("../createShim");
|
||||
|
||||
// port2 will post bridge messages to port 1
|
||||
await createShim(channel.port2);
|
||||
await ShimManager.init();
|
||||
await ShimManager.createShim(channel.port2);
|
||||
|
||||
// bridge -> shim
|
||||
channel.port1.onmessage = ev => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import bridge, { BridgeInfo } from "../../lib/bridge";
|
||||
import options, { Options } from "../../lib/options";
|
||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/utils";
|
||||
|
||||
import { ReceiverSelectorType } from "../../receiver_selectors";
|
||||
import { ReceiverSelectorType } from "../../background/receiverSelector";
|
||||
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
@@ -250,7 +250,7 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
<option value={ ReceiverSelectorType.Popup }>
|
||||
{ _("optionsReceiverSelectorTypeBrowser") }
|
||||
</option>
|
||||
<option value={ ReceiverSelectorType.NativeMac }>
|
||||
<option value={ ReceiverSelectorType.Native }>
|
||||
{ _("optionsReceiverSelectorTypeNative") }
|
||||
</option>
|
||||
</select>
|
||||
|
||||
@@ -7,8 +7,7 @@ import ReactDOM from "react-dom";
|
||||
import { getNextEllipsis } from "../../lib/utils";
|
||||
import { Message, Receiver } from "../../types";
|
||||
|
||||
import { ReceiverSelectorMediaType }
|
||||
from "../../receiver_selectors/ReceiverSelector";
|
||||
import { ReceiverSelectorMediaType } from "../../background/receiverSelector";
|
||||
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
Reference in New Issue
Block a user