mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-13 02:49:58 +00:00
Restructure shim/bridge initialization steps
This commit is contained in:
@@ -168,7 +168,7 @@ async function handleMessage (message) {
|
|||||||
|
|
||||||
browser.on("serviceUp", service => {
|
browser.on("serviceUp", service => {
|
||||||
transforms.encode.write({
|
transforms.encode.write({
|
||||||
subject: "shim:serviceUp"
|
subject: "serviceUp"
|
||||||
, data: {
|
, data: {
|
||||||
address: service.addresses[0]
|
address: service.addresses[0]
|
||||||
, port: service.port
|
, port: service.port
|
||||||
@@ -181,7 +181,7 @@ browser.on("serviceUp", service => {
|
|||||||
|
|
||||||
browser.on("serviceDown", service => {
|
browser.on("serviceDown", service => {
|
||||||
transforms.encode.write({
|
transforms.encode.write({
|
||||||
subject:"shim:serviceDown"
|
subject:"serviceDown"
|
||||||
, data: {
|
, data: {
|
||||||
id: service.txt.id
|
id: service.txt.id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,37 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
document.addEventListener("__castMessageResponse", ev => {
|
const backgroundPort = browser.runtime.connect({
|
||||||
browser.runtime.sendMessage(ev.detail);
|
name: "shim"
|
||||||
})
|
});
|
||||||
|
|
||||||
browser.runtime.onMessage.addListener(message => {
|
backgroundPort.onMessage.addListener(message => {
|
||||||
const event = new CustomEvent("__castMessage", {
|
const event = new CustomEvent("__castMessage", {
|
||||||
detail: JSON.stringify(message)
|
detail: JSON.stringify(message)
|
||||||
});
|
});
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
let popupPort;
|
||||||
|
browser.runtime.onConnect.addListener(port => {
|
||||||
|
if (port.name === "popup") {
|
||||||
|
popupPort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
port.onMessage.addListener(message => {
|
||||||
|
const event = new CustomEvent("__castMessage", {
|
||||||
|
detail: JSON.stringify(message)
|
||||||
|
});
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("__castMessageResponse", ev => {
|
||||||
|
if (ev.detail.destination === "popup") {
|
||||||
|
if (popupPort) {
|
||||||
|
popupPort.postMessage(ev.detail);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
backgroundPort.postMessage(ev.detail);
|
||||||
});
|
});
|
||||||
|
|||||||
220
ext/src/main.js
220
ext/src/main.js
@@ -319,60 +319,15 @@ browser.menus.onClicked.addListener(async (info, tab) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const bridgeMap = new Map();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes native application and handles message
|
|
||||||
* forwarding.
|
|
||||||
*/
|
|
||||||
function initBridge (tabId, frameId) {
|
|
||||||
const existingPort = bridgeMap.get(tabId);
|
|
||||||
|
|
||||||
if (existingPort) {
|
|
||||||
existingPort.disconnect();
|
|
||||||
bridgeMap.delete(tabId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const port = browser.runtime.connectNative(APPLICATION_NAME);
|
|
||||||
|
|
||||||
if (port.error) {
|
|
||||||
console.error(`Failed connect to ${APPLICATION_NAME}:`, port.error.message);
|
|
||||||
} else {
|
|
||||||
bridgeMap.set(tabId, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
port.onDisconnect.addListener(p => {
|
|
||||||
if (p.error) {
|
|
||||||
console.error(`${APPLICATION_NAME} disconnected:`, p.error.message);
|
|
||||||
} else {
|
|
||||||
console.log(`${APPLICATION_NAME} disconnected`);
|
|
||||||
}
|
|
||||||
|
|
||||||
bridgeMap.delete(tabId);
|
|
||||||
});
|
|
||||||
|
|
||||||
port.onMessage.addListener(message => {
|
|
||||||
// Forward shim: messages
|
|
||||||
// TODO: Integrate into messageRouter
|
|
||||||
if (message.subject.startsWith("shim:")) {
|
|
||||||
browser.tabs.sendMessage(tabId, message, { frameId });
|
|
||||||
} else {
|
|
||||||
messageRouter.handleMessage(message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let popupWinId;
|
let popupWinId;
|
||||||
let popupOpenerTabId;
|
let popupShimId;
|
||||||
let popupOpenerFrameId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates popup window for cast destination selection.
|
* Creates popup window for cast destination selection.
|
||||||
* Refocusing other browser windows causes the popup window
|
* Refocusing other browser windows causes the popup window
|
||||||
* to close and returns an API error (TODO).
|
* to close and returns an API error (TODO).
|
||||||
*/
|
*/
|
||||||
async function openPopup (tabId, frameId) {
|
async function openPopup (shimId) {
|
||||||
const width = 350;
|
const width = 350;
|
||||||
const height = 200;
|
const height = 200;
|
||||||
|
|
||||||
@@ -397,8 +352,7 @@ async function openPopup (tabId, frameId) {
|
|||||||
|
|
||||||
// Store popup details for message forwarding
|
// Store popup details for message forwarding
|
||||||
popupWinId = popup.id;
|
popupWinId = popup.id;
|
||||||
popupOpenerTabId = tabId;
|
popupShimId = shimId;
|
||||||
popupOpenerFrameId = frameId;
|
|
||||||
|
|
||||||
// Size/position not set correctly on creation (bug?)
|
// Size/position not set correctly on creation (bug?)
|
||||||
await browser.windows.update(popup.id, {
|
await browser.windows.update(popup.id, {
|
||||||
@@ -422,80 +376,138 @@ async function openPopup (tabId, frameId) {
|
|||||||
browser.windows.onRemoved.addListener(id => {
|
browser.windows.onRemoved.addListener(id => {
|
||||||
if (id === popupWinId) {
|
if (id === popupWinId) {
|
||||||
messageRouter.handleMessage({
|
messageRouter.handleMessage({
|
||||||
subject: "shim:popupClosed"
|
subject: "popupClosed"
|
||||||
});
|
});
|
||||||
|
|
||||||
popupWinId = null;
|
popupWinId = null;
|
||||||
popupOpenerTabId = null;
|
popupShimId = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
const shimMap = new Map();
|
||||||
* Extension scripts make a connection to the background script
|
|
||||||
* with a destination name to be registered as message route.
|
browser.runtime.onMessage.addListener(message => {
|
||||||
*/
|
if (message.subject === "getPopupShimInfo") {
|
||||||
browser.runtime.onConnect.addListener(port => {
|
return new Promise(resolve => {
|
||||||
messageRouter.register(port.name, message => {
|
const { tabId, frameId } = shimMap.get(popupShimId);
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
tabId
|
||||||
|
, frameId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function onConnectShim (port) {
|
||||||
|
const bridgeInfo = await getBridgeInfo();
|
||||||
|
if (bridgeInfo && !bridgeInfo.isVersionCompatible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const tabId = port.sender.tab.id;
|
||||||
|
const frameId = port.sender.frameId;
|
||||||
|
const shimId = `${tabId}:${frameId}`;
|
||||||
|
|
||||||
|
// Disconnect existing shim
|
||||||
|
if (shimMap.has(shimId)) {
|
||||||
|
shimMap.get(shimId).port.disconnect();
|
||||||
|
shimMap.delete(shimId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn bridge app instance
|
||||||
|
const bridgePort = browser.runtime.connectNative(APPLICATION_NAME);
|
||||||
|
|
||||||
|
if (bridgePort.error) {
|
||||||
|
console.error(`Failed connect to ${APPLICATION_NAME}:`
|
||||||
|
, bridgePort.error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
shimMap.set(shimId, {
|
||||||
|
port
|
||||||
|
, bridgePort
|
||||||
|
, tabId
|
||||||
|
, frameId
|
||||||
|
});
|
||||||
|
|
||||||
|
bridgePort.onDisconnect.addListener(() => {
|
||||||
|
if (bridgePort.error) {
|
||||||
|
console.error(`${APPLICATION_NAME} disconnected:`
|
||||||
|
, bridgePort.error.message);
|
||||||
|
} else {
|
||||||
|
console.log(`${APPLICATION_NAME} disconnected`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle disconnect
|
||||||
|
port.onDisconnect.addListener(() => {
|
||||||
|
bridgePort.disconnect();
|
||||||
|
shimMap.delete(shimId);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
bridgePort.onMessage.addListener(message => {
|
||||||
port.postMessage(message);
|
port.postMessage(message);
|
||||||
});
|
});
|
||||||
port.onMessage.addListener(message => {
|
|
||||||
messageRouter.handleMessage(message);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
messageRouter.register("main", async (message, sender) => {
|
port.onMessage.addListener(async message => {
|
||||||
const tabId = sender && sender.tab.id;
|
if (message.subject.startsWith("bridge")) {
|
||||||
|
bridgePort.postMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "main:initialize": {
|
case "openPopup": {
|
||||||
const bridgeInfo = await getBridgeInfo();
|
/**
|
||||||
if (bridgeInfo && bridgeInfo.isVersionCompatible) {
|
* If popup already open, reassign to new shim,
|
||||||
initBridge(tabId, sender.frameId);
|
* otherwise create a new popup.
|
||||||
}
|
*/
|
||||||
|
if (popupWinId) {
|
||||||
|
/**
|
||||||
|
* Notify shim that existing popup has closed and
|
||||||
|
* to re-populate receiver list for new popup.
|
||||||
|
*/
|
||||||
|
port.postMessage({ subject: "popupClosed" });
|
||||||
|
port.postMessage({ subject: "popupReady" });
|
||||||
|
} else {
|
||||||
|
await openPopup(shimId);
|
||||||
|
}
|
||||||
|
|
||||||
browser.tabs.sendMessage(sender.tab.id, {
|
break;
|
||||||
subject: "shim:initialized"
|
};
|
||||||
, data: bridgeInfo
|
|
||||||
}, { frameId: sender.frameId });
|
|
||||||
|
|
||||||
break;
|
case "discover": {
|
||||||
};
|
bridgePort.postMessage({
|
||||||
|
subject: "bridge:discover"
|
||||||
case "main:openPopup": {
|
|
||||||
// If popup already open, reassign opener tab to new shim
|
|
||||||
if (popupWinId) {
|
|
||||||
|
|
||||||
// Notify shim that existing popup is gone
|
|
||||||
messageRouter.handleMessage({
|
|
||||||
subject: "shim:popupClosed"
|
|
||||||
});
|
});
|
||||||
|
|
||||||
popupOpenerTabId = tabId;
|
break;
|
||||||
popupOpenerFrameId = sender.frameId;
|
};
|
||||||
|
|
||||||
// Notify shim to re-populate receiver list
|
default: {
|
||||||
messageRouter.handleMessage({
|
// TODO: Remove need for this
|
||||||
subject: "shim:popupReady"
|
messageRouter.handleMessage(message);
|
||||||
});
|
break;
|
||||||
} else {
|
|
||||||
await openPopup(tabId, sender.frameId);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
port.postMessage({
|
||||||
|
subject: "shimInitialized"
|
||||||
|
, data: bridgeInfo
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.runtime.onConnect.addListener(port => {
|
||||||
|
switch (port.name) {
|
||||||
|
case "shim": {
|
||||||
|
onConnectShim(port);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
messageRouter.register("bridge", (message, sender) => {
|
|
||||||
console.log(message);
|
|
||||||
bridgeMap.get(sender.tab.id).postMessage(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
messageRouter.register("shim", (message, sender) => {
|
|
||||||
browser.tabs.sendMessage(popupOpenerTabId, message
|
|
||||||
, { frameId: popupOpenerFrameId })
|
|
||||||
});
|
|
||||||
|
|
||||||
messageRouter.register("mirrorCast", message => {
|
messageRouter.register("mirrorCast", message => {
|
||||||
browser.tabs.sendMessage(mirrorCastTabId, message
|
browser.tabs.sendMessage(mirrorCastTabId, message
|
||||||
@@ -507,8 +519,12 @@ messageRouter.register("mediaCast", message => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Forward messages into messageRouter
|
||||||
browser.runtime.onMessage.addListener((message, sender) => {
|
browser.runtime.onMessage.addListener((message, sender) => {
|
||||||
messageRouter.handleMessage(message, sender);
|
messageRouter.handleMessage(message, {
|
||||||
|
tabId: sender.tab.id
|
||||||
|
, frameId: sender.frameId
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ function deregister (routeName) {
|
|||||||
routeMap.delete(routeName);
|
routeMap.delete(routeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMessage (message, sender) {
|
function handleMessage (message, details) {
|
||||||
const destination = message.subject.split(":")[0];
|
const destination = message.subject.split(":")[0];
|
||||||
if (routeMap.has(destination)) {
|
if (routeMap.has(destination)) {
|
||||||
routeMap.get(destination)(message, sender);
|
routeMap.get(destination)(message, details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,18 +42,23 @@ class App extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
async componentDidMount () {
|
||||||
this.port = browser.runtime.connect({
|
const { tabId, frameId } = await browser.runtime.sendMessage({
|
||||||
|
subject: "getPopupShimInfo"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.port = browser.tabs.connect(tabId, {
|
||||||
name: "popup"
|
name: "popup"
|
||||||
|
, frameId
|
||||||
});
|
});
|
||||||
|
|
||||||
this.port.postMessage({
|
this.port.postMessage({
|
||||||
subject: "shim:popupReady"
|
subject: "popupReady"
|
||||||
});
|
});
|
||||||
|
|
||||||
this.port.onMessage.addListener(message => {
|
this.port.onMessage.addListener(message => {
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "popup:populate": {
|
case "populateReceiverList": {
|
||||||
this.setState({
|
this.setState({
|
||||||
receivers: message.data.receivers
|
receivers: message.data.receivers
|
||||||
, selectedMedia: message.data.selectedMedia
|
, selectedMedia: message.data.selectedMedia
|
||||||
@@ -70,8 +75,9 @@ class App extends Component {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "popup:close": {
|
case "close": {
|
||||||
window.close();
|
window.close();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +90,7 @@ class App extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.port.postMessage({
|
this.port.postMessage({
|
||||||
subject: "shim:selectReceiver"
|
subject: "selectReceiver"
|
||||||
, data: {
|
, data: {
|
||||||
receiver
|
receiver
|
||||||
, selectedMedia: this.state.selectedMedia
|
, selectedMedia: this.state.selectedMedia
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ cast.initialize = (
|
|||||||
state.apiConfig = apiConfig;
|
state.apiConfig = apiConfig;
|
||||||
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "bridge:discover"
|
subject: "discover"
|
||||||
});
|
});
|
||||||
|
|
||||||
apiConfig.receiverListener(state.receiverList.length
|
apiConfig.receiverListener(state.receiverList.length
|
||||||
@@ -146,7 +146,7 @@ cast.requestSession = (
|
|||||||
|
|
||||||
// Open destination chooser
|
// Open destination chooser
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "main:openPopup"
|
subject: "openPopup"
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -175,11 +175,9 @@ onMessage(message => {
|
|||||||
* Cast destination found (serviceUp). Set the API availability
|
* Cast destination found (serviceUp). Set the API availability
|
||||||
* property and call the page event function (__onGCastApiAvailable).
|
* property and call the page event function (__onGCastApiAvailable).
|
||||||
*/
|
*/
|
||||||
case "shim:serviceUp": {
|
case "serviceUp": {
|
||||||
const receiver = message.data;
|
const receiver = message.data;
|
||||||
|
|
||||||
console.log(receiver);
|
|
||||||
|
|
||||||
if (state.receiverList.find(r => r.id === receiver.id)) {
|
if (state.receiverList.find(r => r.id === receiver.id)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -196,7 +194,7 @@ onMessage(message => {
|
|||||||
* Cast destination lost (serviceDown). Remove from the receiver list
|
* Cast destination lost (serviceDown). Remove from the receiver list
|
||||||
* and update availability state.
|
* and update availability state.
|
||||||
*/
|
*/
|
||||||
case "shim:serviceDown": {
|
case "serviceDown": {
|
||||||
state.receiverList = state.receiverList.filter(
|
state.receiverList = state.receiverList.filter(
|
||||||
receiver => receiver.id !== message.data.id);
|
receiver => receiver.id !== message.data.id);
|
||||||
|
|
||||||
@@ -208,7 +206,7 @@ onMessage(message => {
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
case "shim:selectReceiver": {
|
case "selectReceiver": {
|
||||||
console.info("Caster (Debug): Selected receiver");
|
console.info("Caster (Debug): Selected receiver");
|
||||||
|
|
||||||
const selectedReceiver = new Receiver(
|
const selectedReceiver = new Receiver(
|
||||||
@@ -226,7 +224,8 @@ onMessage(message => {
|
|||||||
, selectedReceiver // receiver
|
, selectedReceiver // receiver
|
||||||
, (session) => {
|
, (session) => {
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "popup:close"
|
subject: "close"
|
||||||
|
, destination: "popup"
|
||||||
});
|
});
|
||||||
|
|
||||||
state.apiConfig.sessionListener(session);
|
state.apiConfig.sessionListener(session);
|
||||||
@@ -258,9 +257,10 @@ onMessage(message => {
|
|||||||
* Popup is ready to receive data to populate the cast destination
|
* Popup is ready to receive data to populate the cast destination
|
||||||
* chooser.
|
* chooser.
|
||||||
*/
|
*/
|
||||||
case "shim:popupReady": {
|
case "popupReady": {
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "popup:populate"
|
subject: "populateReceiverList"
|
||||||
|
, destination: "popup"
|
||||||
, data: {
|
, data: {
|
||||||
receivers: state.receiverList
|
receivers: state.receiverList
|
||||||
, selectedMedia: state.apiConfig._selectedMedia
|
, selectedMedia: state.apiConfig._selectedMedia
|
||||||
@@ -273,7 +273,7 @@ onMessage(message => {
|
|||||||
/**
|
/**
|
||||||
* Popup closed before session established.
|
* Popup closed before session established.
|
||||||
*/
|
*/
|
||||||
case "shim:popupClosed": {
|
case "popupClosed": {
|
||||||
if (state.sessionRequestInProgress) {
|
if (state.sessionRequestInProgress) {
|
||||||
state.sessionRequestInProgress = false;
|
state.sessionRequestInProgress = false;
|
||||||
sessionErrorCallback(new Error_(ErrorCode.CANCEL));
|
sessionErrorCallback(new Error_(ErrorCode.CANCEL));
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ window.chrome.cast.media = media;
|
|||||||
|
|
||||||
onMessage(message => {
|
onMessage(message => {
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "shim:initialized": {
|
case "shimInitialized": {
|
||||||
const bridgeInfo = message.data;
|
const bridgeInfo = message.data;
|
||||||
|
|
||||||
// Call page's API loaded function if defined
|
// Call page's API loaded function if defined
|
||||||
@@ -28,8 +28,3 @@ onMessage(message => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Trigger bridge mDNS discovery
|
|
||||||
sendMessage({
|
|
||||||
subject: "main:initialize"
|
|
||||||
});
|
|
||||||
|
|||||||
Reference in New Issue
Block a user