mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-11 18:19:58 +00:00
Add typed messaging
This commit is contained in:
@@ -16,7 +16,6 @@ import { DecodeTransform
|
|||||||
, EncodeTransform } from "../transforms";
|
, EncodeTransform } from "../transforms";
|
||||||
|
|
||||||
import { ReceiverStatus } from "./castTypes";
|
import { ReceiverStatus } from "./castTypes";
|
||||||
|
|
||||||
import { Message, Receiver } from "./types";
|
import { Message, Receiver } from "./types";
|
||||||
|
|
||||||
import { __applicationName
|
import { __applicationName
|
||||||
@@ -501,7 +500,7 @@ function initialize (options: InitializeOptions) {
|
|||||||
|
|
||||||
function onBrowserServiceUp (service: dnssd.Service) {
|
function onBrowserServiceUp (service: dnssd.Service) {
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "shim:/serviceUp"
|
subject: "main:/serviceUp"
|
||||||
, data: {
|
, data: {
|
||||||
host: service.addresses[0]
|
host: service.addresses[0]
|
||||||
, port: service.port
|
, port: service.port
|
||||||
@@ -513,7 +512,7 @@ function initialize (options: InitializeOptions) {
|
|||||||
|
|
||||||
function onBrowserServiceDown (service: dnssd.Service) {
|
function onBrowserServiceDown (service: dnssd.Service) {
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "shim:/serviceDown"
|
subject: "main:/serviceDown"
|
||||||
, data: {
|
, data: {
|
||||||
id: service.txt.id
|
id: service.txt.id
|
||||||
}
|
}
|
||||||
@@ -533,7 +532,7 @@ function initialize (options: InitializeOptions) {
|
|||||||
|
|
||||||
listener.on("receiverStatus", (status: ReceiverStatus) => {
|
listener.on("receiverStatus", (status: ReceiverStatus) => {
|
||||||
const receiverStatusMessage: any = {
|
const receiverStatusMessage: any = {
|
||||||
subject: "receiverStatus"
|
subject: "main:/receiverStatus"
|
||||||
, data: {
|
, data: {
|
||||||
id
|
id
|
||||||
, status: {
|
, status: {
|
||||||
|
|||||||
@@ -3,11 +3,9 @@
|
|||||||
import bridge from "../lib/bridge";
|
import bridge from "../lib/bridge";
|
||||||
import loadSender from "../lib/loadSender";
|
import loadSender from "../lib/loadSender";
|
||||||
import logger from "../lib/logger";
|
import logger from "../lib/logger";
|
||||||
|
import { Message, Port } from "../lib/messaging";
|
||||||
import options from "../lib/options";
|
import options from "../lib/options";
|
||||||
|
|
||||||
import { Message } from "../types";
|
|
||||||
|
|
||||||
import { getMediaTypesForPageUrl } from "../lib/utils";
|
|
||||||
import { ReceiverSelectionActionType
|
import { ReceiverSelectionActionType
|
||||||
, ReceiverSelectorMediaType } from "./receiverSelector";
|
, ReceiverSelectorMediaType } from "./receiverSelector";
|
||||||
|
|
||||||
@@ -17,11 +15,11 @@ import ReceiverSelectorManager
|
|||||||
import StatusManager from "./StatusManager";
|
import StatusManager from "./StatusManager";
|
||||||
|
|
||||||
|
|
||||||
type Port = browser.runtime.Port | MessagePort;
|
type AnyPort = Port | MessagePort;
|
||||||
|
|
||||||
export interface Shim {
|
export interface Shim {
|
||||||
bridgePort: browser.runtime.Port;
|
bridgePort: Port;
|
||||||
contentPort: Port;
|
contentPort: AnyPort;
|
||||||
contentTabId?: number;
|
contentTabId?: number;
|
||||||
contentFrameId?: number;
|
contentFrameId?: number;
|
||||||
requestedAppId?: string;
|
requestedAppId?: string;
|
||||||
@@ -48,7 +46,7 @@ export default new class ShimManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createShim (port: Port) {
|
public async createShim (port: AnyPort) {
|
||||||
const shim = await (port instanceof MessagePort
|
const shim = await (port instanceof MessagePort
|
||||||
? this.createShimFromBackground(port)
|
? this.createShimFromBackground(port)
|
||||||
: this.createShimFromContent(port));
|
: this.createShimFromContent(port));
|
||||||
@@ -74,20 +72,19 @@ export default new class ShimManager {
|
|||||||
this.activeShims.delete(shim);
|
this.activeShims.delete(shim);
|
||||||
});
|
});
|
||||||
|
|
||||||
shim.bridgePort.onMessage.addListener((message: Message) => {
|
shim.bridgePort.onMessage.addListener(message => {
|
||||||
contentPort.postMessage(message);
|
contentPort.postMessage(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
contentPort.onmessage = ev => {
|
contentPort.addEventListener("message", ev => {
|
||||||
const message = ev.data as Message;
|
this.handleContentMessage(shim, ev.data);
|
||||||
this.handleContentMessage(shim, message);
|
});
|
||||||
};
|
|
||||||
|
|
||||||
return shim;
|
return shim;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createShimFromContent (
|
private async createShimFromContent (
|
||||||
contentPort: browser.runtime.Port): Promise<Shim> {
|
contentPort: Port): Promise<Shim> {
|
||||||
|
|
||||||
if (contentPort.sender?.tab?.id === undefined
|
if (contentPort.sender?.tab?.id === undefined
|
||||||
|| contentPort.sender?.frameId === undefined) {
|
|| contentPort.sender?.frameId === undefined) {
|
||||||
|
|||||||
@@ -2,44 +2,23 @@
|
|||||||
|
|
||||||
import bridge from "../lib/bridge";
|
import bridge from "../lib/bridge";
|
||||||
import logger from "../lib/logger";
|
import logger from "../lib/logger";
|
||||||
|
import { Message, Port } from "../lib/messaging";
|
||||||
|
|
||||||
import { TypedEventTarget } from "../lib/typedEvents";
|
import { TypedEventTarget } from "../lib/TypedEventTarget";
|
||||||
import { Message, Receiver, ReceiverStatus } from "../types";
|
import { Receiver, ReceiverStatus } from "../types";
|
||||||
|
|
||||||
|
|
||||||
interface ReceiverStatusMessage extends Message {
|
|
||||||
subject: "receiverStatus";
|
|
||||||
data: {
|
|
||||||
id: string;
|
|
||||||
status: ReceiverStatus;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ServiceDownMessage extends Message {
|
|
||||||
subject: "shim:/serviceDown";
|
|
||||||
data: {
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ServiceUpMessage extends Message {
|
|
||||||
subject: "shim:/serviceUp";
|
|
||||||
data: Receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface EventMap {
|
interface EventMap {
|
||||||
"serviceUp": ServiceUpMessage["data"];
|
"serviceUp": Receiver;
|
||||||
"serviceDown": ServiceDownMessage["data"];
|
"serviceDown": { id: string };
|
||||||
"statusUpdate": ReceiverStatusMessage["data"];
|
"statusUpdate": { id: string, status: ReceiverStatus };
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:new-parens
|
// tslint:disable-next-line:new-parens
|
||||||
export default new class StatusManager
|
export default new class StatusManager
|
||||||
extends TypedEventTarget<EventMap> {
|
extends TypedEventTarget<EventMap> {
|
||||||
|
|
||||||
private bridgePort: (browser.runtime.Port | null) = null;
|
private bridgePort: (Port | null) = null;
|
||||||
private receivers = new Map<string, Receiver>();
|
private receivers = new Map<string, Receiver>();
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
@@ -97,8 +76,8 @@ export default new class StatusManager
|
|||||||
*/
|
*/
|
||||||
private onBridgePortMessage (message: Message) {
|
private onBridgePortMessage (message: Message) {
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "shim:/serviceUp": {
|
case "main:/serviceUp": {
|
||||||
const { data: receiver } = (message as ServiceUpMessage);
|
const { data: receiver } = message;
|
||||||
this.receivers.set(receiver.id, receiver);
|
this.receivers.set(receiver.id, receiver);
|
||||||
|
|
||||||
const serviceUpEvent = new CustomEvent("serviceUp", {
|
const serviceUpEvent = new CustomEvent("serviceUp", {
|
||||||
@@ -110,8 +89,8 @@ export default new class StatusManager
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "shim:/serviceDown": {
|
case "main:/serviceDown": {
|
||||||
const { data: { id }} = (message as ServiceDownMessage);
|
const { data: { id }} = message;
|
||||||
|
|
||||||
if (this.receivers.has(id)) {
|
if (this.receivers.has(id)) {
|
||||||
this.receivers.delete(id);
|
this.receivers.delete(id);
|
||||||
@@ -126,10 +105,8 @@ export default new class StatusManager
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "receiverStatus": {
|
case "main:/receiverStatus": {
|
||||||
const { data: { id, status }}
|
const { data: { id, status }} = message;
|
||||||
= (message as ReceiverStatusMessage);
|
|
||||||
|
|
||||||
const receiver = this.receivers.get(id);
|
const receiver = this.receivers.get(id);
|
||||||
|
|
||||||
if (!receiver) {
|
if (!receiver) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import defaultOptions from "../defaultOptions";
|
import defaultOptions from "../defaultOptions";
|
||||||
import loadSender from "../lib/loadSender";
|
import loadSender from "../lib/loadSender";
|
||||||
import logger from "../lib/logger";
|
import logger from "../lib/logger";
|
||||||
|
import messaging from "../lib/messaging";
|
||||||
import options from "../lib/options";
|
import options from "../lib/options";
|
||||||
|
|
||||||
import { getChromeUserAgent } from "../lib/userAgents";
|
import { getChromeUserAgent } from "../lib/userAgents";
|
||||||
@@ -617,9 +618,9 @@ async function init () {
|
|||||||
* established, pass it to createShim to handle the setup
|
* established, pass it to createShim to handle the setup
|
||||||
* and maintenance.
|
* and maintenance.
|
||||||
*/
|
*/
|
||||||
browser.runtime.onConnect.addListener(async port => {
|
messaging.onConnect.addListener(async port => {
|
||||||
if (port.name === "shim") {
|
if (port.name === "shim") {
|
||||||
ShimManager.createShim(port);
|
ShimManager.createShim(port as any);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
import bridge from "../../lib/bridge";
|
import bridge from "../../lib/bridge";
|
||||||
import knownApps from "../../lib/knownApps";
|
import knownApps from "../../lib/knownApps";
|
||||||
import logger from "../../lib/logger";
|
import logger from "../../lib/logger";
|
||||||
|
import { Message, Port } from "../../lib/messaging";
|
||||||
import options from "../../lib/options";
|
import options from "../../lib/options";
|
||||||
|
|
||||||
import { TypedEventTarget } from "../../lib/typedEvents";
|
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
||||||
import { getWindowCenteredProps } from "../../lib/utils";
|
import { getWindowCenteredProps } from "../../lib/utils";
|
||||||
import { Message, Receiver } from "../../types";
|
import { Receiver } from "../../types";
|
||||||
|
|
||||||
import ReceiverSelector, {
|
import ReceiverSelector, {
|
||||||
ReceiverSelection
|
ReceiverSelection
|
||||||
@@ -17,27 +18,20 @@ import ReceiverSelector, {
|
|||||||
|
|
||||||
const _ = browser.i18n.getMessage;
|
const _ = browser.i18n.getMessage;
|
||||||
|
|
||||||
|
|
||||||
interface NativeReceiverSelectorSelectedMessage extends Message {
|
|
||||||
subject: "main:/receiverSelector/selected";
|
|
||||||
data: ReceiverSelection;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NativeReceiverSelectorErrorMessage extends Message {
|
|
||||||
subject: "main:/receiverSelector/error";
|
|
||||||
data: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Figure out lifetime properly
|
// TODO: Figure out lifetime properly
|
||||||
export default class NativeReceiverSelector
|
export default class NativeReceiverSelector
|
||||||
extends TypedEventTarget<ReceiverSelectorEvents>
|
extends TypedEventTarget<ReceiverSelectorEvents>
|
||||||
implements ReceiverSelector {
|
implements ReceiverSelector {
|
||||||
|
|
||||||
private bridgePort: (browser.runtime.Port | null) = null;
|
private bridgePort: (Port | null) = null;
|
||||||
private wasReceiverSelected: boolean = false;
|
private wasReceiverSelected: boolean = false;
|
||||||
private _isOpen: boolean = false;
|
private _isOpen: boolean = false;
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
super();
|
||||||
|
this.onBridgePortMessage = this.onBridgePortMessage.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
get isOpen () {
|
get isOpen () {
|
||||||
return this._isOpen;
|
return this._isOpen;
|
||||||
}
|
}
|
||||||
@@ -50,31 +44,7 @@ export default class NativeReceiverSelector
|
|||||||
|
|
||||||
this.bridgePort = await bridge.connect();
|
this.bridgePort = await bridge.connect();
|
||||||
|
|
||||||
this.bridgePort.onMessage.addListener((message: Message) => {
|
this.bridgePort.onMessage.addListener(this.onBridgePortMessage);
|
||||||
switch (message.subject) {
|
|
||||||
case "main:/receiverSelector/selected": {
|
|
||||||
this.onBridgePortMessageSelected(
|
|
||||||
message as NativeReceiverSelectorSelectedMessage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "main:/receiverSelector/error": {
|
|
||||||
this.onBridgePortMessageError(
|
|
||||||
message as NativeReceiverSelectorErrorMessage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "main:/receiverSelector/close": {
|
|
||||||
this.onBridgePortMessageClose();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "main:/receiverSelector/stop": {
|
|
||||||
this.dispatchEvent(new CustomEvent("stop", {
|
|
||||||
detail: message.data
|
|
||||||
}));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.bridgePort.onDisconnect.addListener(() => {
|
this.bridgePort.onDisconnect.addListener(() => {
|
||||||
this.bridgePort = null;
|
this.bridgePort = null;
|
||||||
this.wasReceiverSelected = false;
|
this.wasReceiverSelected = false;
|
||||||
@@ -128,40 +98,46 @@ export default class NativeReceiverSelector
|
|||||||
this._isOpen = false;
|
this._isOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async onBridgePortMessage (message: Message) {
|
||||||
|
switch (message.subject) {
|
||||||
|
case "main:/receiverSelector/selected": {
|
||||||
|
this.wasReceiverSelected = true;
|
||||||
|
this.dispatchEvent(new CustomEvent("selected", {
|
||||||
|
detail: message.data
|
||||||
|
}));
|
||||||
|
|
||||||
private async onBridgePortMessageSelected (
|
if (!(await options.get("receiverSelectorWaitForConnection"))) {
|
||||||
message: NativeReceiverSelectorSelectedMessage) {
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
this.wasReceiverSelected = true;
|
break;
|
||||||
|
}
|
||||||
|
case "main:/receiverSelector/error": {
|
||||||
|
logger.error("Native receiver selector error", message.data);
|
||||||
|
this.dispatchEvent(new CustomEvent("error"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "main:/receiverSelector/close": {
|
||||||
|
if (!this.wasReceiverSelected) {
|
||||||
|
this.dispatchEvent(new CustomEvent("cancelled"));
|
||||||
|
}
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent("selected", {
|
if (this.bridgePort) {
|
||||||
detail: message.data
|
this.bridgePort.disconnect();
|
||||||
}));
|
}
|
||||||
|
|
||||||
if (!(await options.get("receiverSelectorWaitForConnection"))) {
|
this.bridgePort = null;
|
||||||
this.close();
|
this.wasReceiverSelected = false;
|
||||||
|
this._isOpen = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "main:/receiverSelector/stop": {
|
||||||
|
this.dispatchEvent(new CustomEvent("stop", {
|
||||||
|
detail: message.data
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onBridgePortMessageError (
|
|
||||||
message: NativeReceiverSelectorErrorMessage) {
|
|
||||||
|
|
||||||
logger.error("Native receiver selector error", message.data);
|
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent("error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async onBridgePortMessageClose () {
|
|
||||||
if (!this.wasReceiverSelected) {
|
|
||||||
this.dispatchEvent(new CustomEvent("cancelled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.bridgePort) {
|
|
||||||
this.bridgePort.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bridgePort = null;
|
|
||||||
this.wasReceiverSelected = false;
|
|
||||||
this._isOpen = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ import ReceiverSelector, {
|
|||||||
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
||||||
|
|
||||||
import logger from "../../lib/logger";
|
import logger from "../../lib/logger";
|
||||||
|
import messaging, { Port, Message } from "../../lib/messaging";
|
||||||
import options from "../../lib/options";
|
import options from "../../lib/options";
|
||||||
|
|
||||||
import { TypedEventTarget } from "../../lib/typedEvents";
|
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
||||||
import { getWindowCenteredProps, WindowCenteredProps } from "../../lib/utils";
|
import { getWindowCenteredProps, WindowCenteredProps } from "../../lib/utils";
|
||||||
import { Message, Receiver } from "../../types";
|
import { Receiver } from "../../types";
|
||||||
|
|
||||||
|
|
||||||
const POPUP_URL = browser.runtime.getURL("ui/popup/index.html");
|
const POPUP_URL = browser.runtime.getURL("ui/popup/index.html");
|
||||||
@@ -20,7 +21,7 @@ export default class PopupReceiverSelector
|
|||||||
|
|
||||||
private windowId?: number;
|
private windowId?: number;
|
||||||
|
|
||||||
private messagePort?: browser.runtime.Port;
|
private messagePort?: Port;
|
||||||
private messagePortDisconnected?: boolean;
|
private messagePortDisconnected?: boolean;
|
||||||
|
|
||||||
private receivers?: Receiver[];
|
private receivers?: Receiver[];
|
||||||
@@ -37,6 +38,7 @@ export default class PopupReceiverSelector
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
// Bind methods to pass to addListener
|
// Bind methods to pass to addListener
|
||||||
|
this.onConnect = this.onConnect.bind(this);
|
||||||
this.onPopupMessage = this.onPopupMessage.bind(this);
|
this.onPopupMessage = this.onPopupMessage.bind(this);
|
||||||
this.onWindowsRemoved = this.onWindowsRemoved.bind(this);
|
this.onWindowsRemoved = this.onWindowsRemoved.bind(this);
|
||||||
this.onWindowsFocusChanged = this.onWindowsFocusChanged.bind(this);
|
this.onWindowsFocusChanged = this.onWindowsFocusChanged.bind(this);
|
||||||
@@ -47,39 +49,7 @@ export default class PopupReceiverSelector
|
|||||||
* Handle incoming message channel connection from popup
|
* Handle incoming message channel connection from popup
|
||||||
* window script.
|
* window script.
|
||||||
*/
|
*/
|
||||||
browser.runtime.onConnect.addListener(port => {
|
messaging.onConnect.addListener(this.onConnect);
|
||||||
// Don't pollute history
|
|
||||||
browser.history.deleteUrl({ url: POPUP_URL });
|
|
||||||
|
|
||||||
if (port.name !== "popup") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnect existing port
|
|
||||||
if (this.messagePort) {
|
|
||||||
this.messagePort.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.messagePort = port;
|
|
||||||
this.messagePort.onMessage.addListener(this.onPopupMessage);
|
|
||||||
this.messagePort.onDisconnect.addListener(() => {
|
|
||||||
this.messagePortDisconnected = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.messagePort.postMessage({
|
|
||||||
subject: "popup:/sendRequestedAppId"
|
|
||||||
, data: { requestedAppId: this.requestedAppId }
|
|
||||||
});
|
|
||||||
|
|
||||||
this.messagePort.postMessage({
|
|
||||||
subject: "popup:/populateReceiverList"
|
|
||||||
, data: {
|
|
||||||
receivers: this.receivers
|
|
||||||
, defaultMediaType: this.defaultMediaType
|
|
||||||
, availableMediaTypes: this.availableMediaTypes
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get isOpen () {
|
get isOpen () {
|
||||||
@@ -162,6 +132,46 @@ export default class PopupReceiverSelector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onConnect (port: Port) {
|
||||||
|
browser.history.deleteUrl({ url: POPUP_URL });
|
||||||
|
|
||||||
|
if (port.name !== "popup") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.messagePort) {
|
||||||
|
this.messagePort.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messagePort = port;
|
||||||
|
this.messagePort.onMessage.addListener(this.onPopupMessage);
|
||||||
|
this.messagePort.onDisconnect.addListener(() => {
|
||||||
|
this.messagePortDisconnected = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.requestedAppId
|
||||||
|
|| !this.receivers
|
||||||
|
|| !this.defaultMediaType
|
||||||
|
|| !this.availableMediaTypes) {
|
||||||
|
throw logger.error("Popup receiver data not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messagePort.postMessage({
|
||||||
|
subject: "popup:/sendRequestedAppId"
|
||||||
|
, data: { requestedAppId: this.requestedAppId }
|
||||||
|
});
|
||||||
|
|
||||||
|
this.messagePort.postMessage({
|
||||||
|
subject: "popup:/populateReceiverList"
|
||||||
|
, data: {
|
||||||
|
receivers: this.receivers
|
||||||
|
, defaultMediaType: this.defaultMediaType
|
||||||
|
, availableMediaTypes: this.availableMediaTypes
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
messaging.onConnect.removeListener(this.onConnect);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles popup messages.
|
* Handles popup messages.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { TypedEventTarget } from "../../lib/typedEvents";
|
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
||||||
import { Receiver } from "../../types";
|
import { Receiver } from "../../types";
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
export interface TypedEvents {
|
interface TypedEvents {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
59
ext/src/lib/TypedPort.ts
Normal file
59
ext/src/lib/TypedPort.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const portMap = new WeakMap<any, browser.runtime.Port>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows typed access to a runtime.Port object.
|
||||||
|
*/
|
||||||
|
export class TypedPort<T extends any[]> {
|
||||||
|
public name: string;
|
||||||
|
public error: { message: string };
|
||||||
|
public sender?: browser.runtime.MessageSender;
|
||||||
|
|
||||||
|
constructor (port: browser.runtime.Port) {
|
||||||
|
portMap.set(this, port);
|
||||||
|
this.name = port.name;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
this.error = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnect () {
|
||||||
|
portMap.get(this)?.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onDisconnect = {
|
||||||
|
addListener: (cb: (port: TypedPort<T>) => void) => {
|
||||||
|
portMap.get(this)?.onDisconnect.addListener(cb as any);
|
||||||
|
}
|
||||||
|
, removeListener: (cb: (port: TypedPort<T>) => void) => {
|
||||||
|
portMap.get(this)?.onDisconnect.addListener(cb as any);
|
||||||
|
}
|
||||||
|
, hasListener: (cb: (port: TypedPort<T>) => void) => {
|
||||||
|
return portMap.get(this)?.onDisconnect.hasListener(cb as any)
|
||||||
|
?? false;
|
||||||
|
}
|
||||||
|
, hasListeners: () => {
|
||||||
|
return portMap.get(this)?.onMessage.hasListeners() ?? false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public onMessage = {
|
||||||
|
addListener: (cb: (message: T[number]) => void) => {
|
||||||
|
portMap.get(this)?.onMessage.addListener(cb);
|
||||||
|
}
|
||||||
|
, removeListener: (cb: (message: T[number]) => void) => {
|
||||||
|
portMap.get(this)?.onMessage.removeListener(cb);
|
||||||
|
}
|
||||||
|
, hasListener: (cb: (message: T[number]) => void) => {
|
||||||
|
return portMap.get(this)?.onMessage.hasListener(cb as any) ?? false;
|
||||||
|
}
|
||||||
|
, hasListeners: () => {
|
||||||
|
return portMap.get(this)?.onMessage.hasListeners() ?? false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public postMessage (message: T[number]) {
|
||||||
|
portMap.get(this)?.postMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,14 +13,6 @@ export class TypedStorageArea<Schema extends { [key: string]: any }> {
|
|||||||
this.storageArea = storageArea;
|
this.storageArea = storageArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves one or more items from the storage area.
|
|
||||||
*
|
|
||||||
* @param keys -
|
|
||||||
* A string, array of strings or partial schema object
|
|
||||||
* (with default values) indicating which keys to retrieve
|
|
||||||
* from storage.
|
|
||||||
*/
|
|
||||||
public async get<SchemaKey extends keyof Schema
|
public async get<SchemaKey extends keyof Schema
|
||||||
, SchemaPartial extends Partial<Schema>> (
|
, SchemaPartial extends Partial<Schema>> (
|
||||||
keys?: SchemaKey
|
keys?: SchemaKey
|
||||||
@@ -33,47 +25,22 @@ export class TypedStorageArea<Schema extends { [key: string]: any }> {
|
|||||||
return await this.storageArea.get(keys);
|
return await this.storageArea.get(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the amount of storage space — in bytes — used by one
|
|
||||||
* or more items in the storage area.
|
|
||||||
*
|
|
||||||
* @param keys -
|
|
||||||
* A string or array of strings indicating the keys of
|
|
||||||
* which to get the storage space.
|
|
||||||
*/
|
|
||||||
public async getBytesInUse<SchemaKey extends keyof Schema> (
|
public async getBytesInUse<SchemaKey extends keyof Schema> (
|
||||||
keys?: Schema | SchemaKey[]): Promise<number> {
|
keys?: Schema | SchemaKey[]): Promise<number> {
|
||||||
|
|
||||||
return await this.storageArea.getBytesInUse(keys);
|
return await this.storageArea.getBytesInUse(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores one or more items in the storage area.
|
|
||||||
*
|
|
||||||
* @param keys -
|
|
||||||
* A partial schema object containing the items to be
|
|
||||||
* stored or updated.
|
|
||||||
*/
|
|
||||||
public async set (keys: Partial<Schema>): Promise<void> {
|
public async set (keys: Partial<Schema>): Promise<void> {
|
||||||
await this.storageArea.set(keys);
|
await this.storageArea.set(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes one or more items from the storage area.
|
|
||||||
*
|
|
||||||
* @param keys -
|
|
||||||
* A string or array of strings indicating which keys to
|
|
||||||
* remove from storage.
|
|
||||||
*/
|
|
||||||
public async remove<SchemaKey extends keyof Schema> (
|
public async remove<SchemaKey extends keyof Schema> (
|
||||||
keys: SchemaKey | SchemaKey[]): Promise<void> {
|
keys: SchemaKey | SchemaKey[]): Promise<void> {
|
||||||
|
|
||||||
await this.storageArea.remove(keys);
|
await this.storageArea.remove(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all items from the storage area.
|
|
||||||
*/
|
|
||||||
public async clear (): Promise<void> {
|
public async clear (): Promise<void> {
|
||||||
await this.storageArea.clear();
|
await this.storageArea.clear();
|
||||||
}
|
}
|
||||||
@@ -2,14 +2,22 @@
|
|||||||
|
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
|
|
||||||
|
import { TypedPort } from "./TypedPort";
|
||||||
|
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
|
import { Messages, Message, Port } from "./messaging";
|
||||||
import nativeMessaging from "./nativeMessaging";
|
import nativeMessaging from "./nativeMessaging";
|
||||||
import options from "./options";
|
import options from "./options";
|
||||||
|
|
||||||
|
import { Receiver } from "../types";
|
||||||
|
import { ReceiverSelectionCast
|
||||||
|
, ReceiverSelectionStop } from "../background/receiverSelector/ReceiverSelector";
|
||||||
|
|
||||||
async function connect (): Promise<browser.runtime.Port> {
|
|
||||||
|
async function connect (): Promise<Port> {
|
||||||
const applicationName = await options.get("bridgeApplicationName");
|
const applicationName = await options.get("bridgeApplicationName");
|
||||||
const bridgePort = nativeMessaging.connectNative(applicationName);
|
const bridgePort = nativeMessaging.connectNative(applicationName) as
|
||||||
|
unknown as Port;
|
||||||
|
|
||||||
bridgePort.onDisconnect.addListener(() => {
|
bridgePort.onDisconnect.addListener(() => {
|
||||||
if (bridgePort.error) {
|
if (bridgePort.error) {
|
||||||
|
|||||||
213
ext/src/lib/messaging.ts
Normal file
213
ext/src/lib/messaging.ts
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { TypedPort } from "./TypedPort";
|
||||||
|
|
||||||
|
import { BridgeInfo } from "./bridge";
|
||||||
|
import { Receiver, ReceiverStatus } from "../types";
|
||||||
|
import { ReceiverSelectorMediaType } from "../background/receiverSelector";
|
||||||
|
import { ReceiverSelection
|
||||||
|
, ReceiverSelectionCast
|
||||||
|
, ReceiverSelectionStop } from "../background/receiverSelector/ReceiverSelector";
|
||||||
|
|
||||||
|
import Volume from "../shim/cast/classes/Volume";
|
||||||
|
import { MediaInfo } from "../shim/cast/media";
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Document messages properly
|
||||||
|
export type Messages = [
|
||||||
|
{
|
||||||
|
subject: "popup:/sendRequestedAppId"
|
||||||
|
, data: {
|
||||||
|
requestedAppId: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "popup:/populateReceiverList"
|
||||||
|
, data: {
|
||||||
|
receivers: Receiver[]
|
||||||
|
, defaultMediaType: ReceiverSelectorMediaType
|
||||||
|
, availableMediaTypes: ReceiverSelectorMediaType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, { subject: "receiverSelector:/selected", data: ReceiverSelection }
|
||||||
|
, { subject: "receiverSelector:/stop", data: ReceiverSelection }
|
||||||
|
, { subject: "main:/shimInitialized", data: { appId: string; }}
|
||||||
|
, { subject: "main:/selectReceiverBegin" }
|
||||||
|
, { subject: "shim:/selectReceiverEnd", data: ReceiverSelectionCast }
|
||||||
|
, { subject: "shim:/selectReceiverStop", data: ReceiverSelectionStop }
|
||||||
|
, { subject: "shim:/selectReceiverCancelled" }
|
||||||
|
, { subject: "main:/sessionCreated" }
|
||||||
|
, { subject: "shim:/serviceUp", data: { id: Receiver["id"] }}
|
||||||
|
, { subject: "shim:/serviceDown", data: { id: Receiver["id"] }}
|
||||||
|
, { subject: "shim:/initialized", data: BridgeInfo }
|
||||||
|
, { subject: "shim:/launchApp", data: { receiver: Receiver }}
|
||||||
|
|
||||||
|
// Session messages
|
||||||
|
, { subject: "shim:/session/stopped" }
|
||||||
|
, {
|
||||||
|
subject: "shim:/session/connected"
|
||||||
|
, data: {
|
||||||
|
sessionId: string;
|
||||||
|
namespaces: Array<{ name: string }>;
|
||||||
|
displayName: string;
|
||||||
|
statusText: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "shim:/session/updateStatus"
|
||||||
|
, data: { volume: Volume }
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "shim:/session/impl_addMessageListener"
|
||||||
|
, data: { namespace: string, data: string }
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "shim:/session/impl_sendMessage"
|
||||||
|
, data: { messageId: string, error: boolean }
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "shim:/session/impl_setReceiverMuted"
|
||||||
|
, data: { volumeId: string, error: boolean }
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "shim:/session/impl_setReceiverVolumeLevel"
|
||||||
|
, data: { volumeId: string, error: boolean }
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "shim:/session/impl_stop"
|
||||||
|
, data: { stopId: string, error: boolean }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bridge session messages
|
||||||
|
, {
|
||||||
|
subject: "bridge:/session/impl_leave"
|
||||||
|
, data: { id: string }
|
||||||
|
, _id: string
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "bridge:/session/impl_sendMessage"
|
||||||
|
, data: { namespace: string, message: any, messageId: string }
|
||||||
|
, _id: string
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "bridge:/session/impl_setReceiverMuted"
|
||||||
|
, data: { muted: boolean, volumeId: string }
|
||||||
|
, _id: string
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "bridge:/session/impl_setReceiverVolumeLevel"
|
||||||
|
, data: { newLevel: number, volumeId: string }
|
||||||
|
, _id: string
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "bridge:/session/impl_stop"
|
||||||
|
, data: { stopId: string }
|
||||||
|
, _id: string
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "bridge:/session/impl_addMessageListener"
|
||||||
|
, data: { namespace: string }
|
||||||
|
, _id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Media messages
|
||||||
|
, {
|
||||||
|
subject: "shim:/media/update"
|
||||||
|
, data: {
|
||||||
|
currentTime: number
|
||||||
|
, _lastCurrentTime: number
|
||||||
|
, customData: any
|
||||||
|
, playbackRate: number
|
||||||
|
, playerState: string
|
||||||
|
, repeatMode: string
|
||||||
|
, _volumeLevel: number
|
||||||
|
, _volumeMuted: boolean
|
||||||
|
, media: MediaInfo
|
||||||
|
, mediaSessionId: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "shim:/media/sendMediaMessageResponse"
|
||||||
|
, data: { messageId: string, error: boolean }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bridge media messages
|
||||||
|
, {
|
||||||
|
subject: "bridge:/media/initialize"
|
||||||
|
, data: {
|
||||||
|
sessionId: string
|
||||||
|
, mediaSessionId: number
|
||||||
|
, _internalSessionId: string
|
||||||
|
}
|
||||||
|
, _id: string;
|
||||||
|
}
|
||||||
|
, {
|
||||||
|
subject: "bridge:/media/sendMediaMessage"
|
||||||
|
, data: { message: any, messageId: string }
|
||||||
|
, _id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bridge messages
|
||||||
|
, { subject: "main:/receiverSelector/selected", data: ReceiverSelectionCast }
|
||||||
|
, { subject: "main:/receiverSelector/error", data: string }
|
||||||
|
, { subject: "main:/receiverSelector/close" }
|
||||||
|
, { subject: "main:/receiverSelector/stop", data: ReceiverSelectionStop }
|
||||||
|
|
||||||
|
, { subject: "bridge:/initialize", data: { shouldWatchStatus: boolean }}
|
||||||
|
, { subject: "bridge:/receiverSelector/open", data: any }
|
||||||
|
, { subject: "bridge:/receiverSelector/close" }
|
||||||
|
, { subject: "bridge:/stopReceiverApp", data: { receiver: Receiver }}
|
||||||
|
, {
|
||||||
|
subject: "bridge:/session/initialize"
|
||||||
|
, data: {
|
||||||
|
address: string
|
||||||
|
, port: number
|
||||||
|
, appId: string
|
||||||
|
, sessionId: string
|
||||||
|
}
|
||||||
|
, _id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
, { subject: "main:/serviceUp", data: Receiver }
|
||||||
|
, { subject: "main:/serviceDown", data: { id: string }}
|
||||||
|
, {
|
||||||
|
subject: "main:/receiverStatus"
|
||||||
|
, data: { id: string, status: ReceiverStatus }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export type Port = TypedPort<Messages>;
|
||||||
|
export type Message = Messages[number];
|
||||||
|
|
||||||
|
|
||||||
|
interface RuntimeConnectInfo {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
interface TabConnectInfo {
|
||||||
|
name: string;
|
||||||
|
frameId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
connect (connectInfo: RuntimeConnectInfo) {
|
||||||
|
return browser.runtime.connect(connectInfo) as
|
||||||
|
unknown as TypedPort<Messages>;
|
||||||
|
}
|
||||||
|
|
||||||
|
, connectTab (tabId: number, connectInfo: TabConnectInfo) {
|
||||||
|
return browser.tabs.connect(tabId, connectInfo) as
|
||||||
|
unknown as TypedPort<Messages>;
|
||||||
|
}
|
||||||
|
|
||||||
|
, onConnect: {
|
||||||
|
addListener (cb: (port: TypedPort<Messages>) => void) {
|
||||||
|
browser.runtime.onConnect.addListener(cb as any);
|
||||||
|
}
|
||||||
|
, removeListener (cb: (port: TypedPort<Messages>) => void) {
|
||||||
|
browser.runtime.onConnect.removeListener(cb as any);
|
||||||
|
}
|
||||||
|
, hasListener (cb: (port: TypedPort<Messages>) => void) {
|
||||||
|
return browser.runtime.onConnect.hasListener(cb as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -5,8 +5,8 @@ import defaultOptions from "../defaultOptions";
|
|||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
|
|
||||||
import { ReceiverSelectorType } from "../background/receiverSelector";
|
import { ReceiverSelectorType } from "../background/receiverSelector";
|
||||||
import { TypedEventTarget } from "./typedEvents";
|
import { TypedEventTarget } from "./TypedEventTarget";
|
||||||
import { TypedStorageArea } from "./typedStorage";
|
import { TypedStorageArea } from "./TypedStorageArea";
|
||||||
|
|
||||||
|
|
||||||
const storageArea = new TypedStorageArea<{
|
const storageArea = new TypedStorageArea<{
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const _stopCallbacks = new WeakMap<Session, CallbacksMap>();
|
|||||||
|
|
||||||
export default class Session {
|
export default class Session {
|
||||||
public media: Media[];
|
public media: Media[];
|
||||||
public namespaces: Array<{ name: "string" }>;
|
public namespaces: Array<{ name: string }>;
|
||||||
public senderApps: SenderApplication[];
|
public senderApps: SenderApplication[];
|
||||||
public status: SessionStatus;
|
public status: SessionStatus;
|
||||||
public statusText: string | null;
|
public statusText: string | null;
|
||||||
@@ -91,13 +91,14 @@ export default class Session {
|
|||||||
, appId
|
, appId
|
||||||
, sessionId
|
, sessionId
|
||||||
}
|
}
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const listenerObject = onMessage(message => {
|
const listenerObject = onMessage(message => {
|
||||||
// Filter other session messages
|
// Filter other session messages
|
||||||
if (message._id && message._id !== _id.get(this)) {
|
if ((message as any)._id
|
||||||
|
&& (message as any)._id !== _id.get(this)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,9 +165,7 @@ export default class Session {
|
|||||||
|
|
||||||
|
|
||||||
case "shim:/session/impl_addMessageListener": {
|
case "shim:/session/impl_addMessageListener": {
|
||||||
const { namespace, data }
|
const { namespace, data } = message.data;
|
||||||
: { namespace: string, data: string } = message.data;
|
|
||||||
|
|
||||||
const messageListeners = _messageListeners
|
const messageListeners = _messageListeners
|
||||||
.get(this)?.get(namespace);
|
.get(this)?.get(namespace);
|
||||||
|
|
||||||
@@ -180,9 +179,7 @@ export default class Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "shim:/session/impl_sendMessage": {
|
case "shim:/session/impl_sendMessage": {
|
||||||
const { messageId, error }
|
const { messageId, error } = message.data;
|
||||||
: { messageId: string, error: boolean } = message.data;
|
|
||||||
|
|
||||||
const [ successCallback, errorCallback ] =
|
const [ successCallback, errorCallback ] =
|
||||||
_sendMessageCallbacks
|
_sendMessageCallbacks
|
||||||
.get(this)?.get(messageId) ?? [];
|
.get(this)?.get(messageId) ?? [];
|
||||||
@@ -286,7 +283,7 @@ export default class Session {
|
|||||||
sendMessageResponse({
|
sendMessageResponse({
|
||||||
subject: "bridge:/session/impl_addMessageListener"
|
subject: "bridge:/session/impl_addMessageListener"
|
||||||
, data: { namespace }
|
, data: { namespace }
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +300,7 @@ export default class Session {
|
|||||||
sendMessageResponse({
|
sendMessageResponse({
|
||||||
subject: "bridge:/session/impl_leave"
|
subject: "bridge:/session/impl_leave"
|
||||||
, data: { id }
|
, data: { id }
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
|
|
||||||
_leaveCallbacks.get(this)?.set(id, [
|
_leaveCallbacks.get(this)?.set(id, [
|
||||||
@@ -411,7 +408,7 @@ export default class Session {
|
|||||||
, message
|
, message
|
||||||
, messageId
|
, messageId
|
||||||
}
|
}
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
|
|
||||||
_sendMessageCallbacks.get(this)?.set(messageId, [
|
_sendMessageCallbacks.get(this)?.set(messageId, [
|
||||||
@@ -430,7 +427,7 @@ export default class Session {
|
|||||||
sendMessageResponse({
|
sendMessageResponse({
|
||||||
subject: "bridge:/session/impl_setReceiverMuted"
|
subject: "bridge:/session/impl_setReceiverMuted"
|
||||||
, data: { muted, volumeId }
|
, data: { muted, volumeId }
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
|
|
||||||
_setReceiverMutedCallbacks.get(this)?.set(volumeId, [
|
_setReceiverMutedCallbacks.get(this)?.set(volumeId, [
|
||||||
@@ -449,7 +446,7 @@ export default class Session {
|
|||||||
sendMessageResponse({
|
sendMessageResponse({
|
||||||
subject: "bridge:/session/impl_setReceiverVolumeLevel"
|
subject: "bridge:/session/impl_setReceiverVolumeLevel"
|
||||||
, data: { newLevel, volumeId }
|
, data: { newLevel, volumeId }
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
|
|
||||||
_setReceiverVolumeLevelCallbacks.get(this)?.set(volumeId, [
|
_setReceiverVolumeLevelCallbacks.get(this)?.set(volumeId, [
|
||||||
@@ -467,7 +464,7 @@ export default class Session {
|
|||||||
sendMessageResponse({
|
sendMessageResponse({
|
||||||
subject: "bridge:/session/impl_stop"
|
subject: "bridge:/session/impl_stop"
|
||||||
, data: { stopId }
|
, data: { stopId }
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
|
|
||||||
_stopCallbacks.get(this)?.set(stopId, [
|
_stopCallbacks.get(this)?.set(stopId, [
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ type ErrorCallback = (err: Error_) => void;
|
|||||||
|
|
||||||
let apiConfig: ApiConfig;
|
let apiConfig: ApiConfig;
|
||||||
|
|
||||||
const receiverList: Receiver[] = [];
|
const receiverList: Array<{ id: string }> = [];
|
||||||
const sessionList: Session[] = [];
|
const sessionList: Session[] = [];
|
||||||
|
|
||||||
const receiverActionListeners = new Set<ReceiverActionListener>();
|
const receiverActionListeners = new Set<ReceiverActionListener>();
|
||||||
|
|||||||
@@ -76,11 +76,12 @@ export default class Media {
|
|||||||
, mediaSessionId
|
, mediaSessionId
|
||||||
, _internalSessionId
|
, _internalSessionId
|
||||||
}
|
}
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
|
|
||||||
onMessage(message => {
|
onMessage(message => {
|
||||||
if (!message._id || message._id !== _id.get(this)) {
|
if ((message as any)._id
|
||||||
|
&& (message as any)._id !== _id.get(this)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ export default class Media {
|
|||||||
this.playerState = status.playerState;
|
this.playerState = status.playerState;
|
||||||
this.repeatMode = status.repeatMode;
|
this.repeatMode = status.repeatMode;
|
||||||
|
|
||||||
if (status.volume) {
|
if (status._volumeLevel && status._volumeMuted) {
|
||||||
this.volume = new Volume(
|
this.volume = new Volume(
|
||||||
status._volumeLevel
|
status._volumeLevel
|
||||||
, status._volumeMuted);
|
, status._volumeMuted);
|
||||||
@@ -120,9 +121,7 @@ export default class Media {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "shim:/media/sendMediaMessageResponse": {
|
case "shim:/media/sendMediaMessageResponse": {
|
||||||
const { messageId, error }
|
const { messageId, error } = message.data;
|
||||||
: { messageId: string, error: any } = message.data;
|
|
||||||
|
|
||||||
const [ successCallback, errorCallback ]
|
const [ successCallback, errorCallback ]
|
||||||
= _sendMediaMessageCallbacks
|
= _sendMediaMessageCallbacks
|
||||||
.get(this)?.get(messageId) ?? [];
|
.get(this)?.get(messageId) ?? [];
|
||||||
@@ -323,7 +322,7 @@ export default class Media {
|
|||||||
message
|
message
|
||||||
, messageId
|
, messageId
|
||||||
}
|
}
|
||||||
, _id: _id.get(this)
|
, _id: _id.get(this)!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { loadScript } from "../lib/utils";
|
import { loadScript } from "../lib/utils";
|
||||||
import { Message } from "../types";
|
|
||||||
import { onMessageResponse, sendMessage } from "./eventMessageChannel";
|
import { onMessageResponse, sendMessage } from "./eventMessageChannel";
|
||||||
|
|
||||||
|
import messaging, { Message } from "../lib/messaging";
|
||||||
|
|
||||||
|
|
||||||
const { isFramework }
|
const { isFramework }
|
||||||
: { isFramework: boolean } = (window as any);
|
: { isFramework: boolean } = (window as any);
|
||||||
@@ -18,7 +19,7 @@ if (isFramework) {
|
|||||||
|
|
||||||
|
|
||||||
// Message port to background script
|
// Message port to background script
|
||||||
export const backgroundPort = browser.runtime.connect({ name: "shim" });
|
export const backgroundPort = messaging.connect({ name: "shim" });
|
||||||
|
|
||||||
const forwardToShim = (message: Message) => sendMessage(message);
|
const forwardToShim = (message: Message) => sendMessage(message);
|
||||||
const forwardToMain = (message: Message) => backgroundPort.postMessage(message);
|
const forwardToMain = (message: Message) => backgroundPort.postMessage(message);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { Message } from "../types";
|
import { Message } from "../lib/messaging";
|
||||||
|
|
||||||
|
|
||||||
type ListenerFunc = (message: Message) => void;
|
type ListenerFunc = (message: Message) => void;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import * as cast from "./cast";
|
import * as cast from "./cast";
|
||||||
|
import { Message } from "../lib/messaging";
|
||||||
|
|
||||||
import { BridgeInfo } from "../lib/bridge";
|
import { BridgeInfo } from "../lib/bridge";
|
||||||
import { Message } from "../types";
|
|
||||||
|
|
||||||
import { onMessage
|
import { onMessage
|
||||||
, onMessageResponse
|
, onMessageResponse
|
||||||
|
|||||||
Reference in New Issue
Block a user