mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 18:39:58 +00:00
Add bridge debug info to options page
This commit is contained in:
@@ -97,11 +97,11 @@ async function handleMessage (message) {
|
|||||||
|
|
||||||
|
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "bridge:initialize": {
|
case "bridge:getInfo": {
|
||||||
const extensionVersion = message.data;
|
const extensionVersion = message.data;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subject: "main:bridgeInitialized"
|
subject: "main:bridgeInfo"
|
||||||
, data: __applicationVersion
|
, data: __applicationVersion
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
, "optionsBridgeCategoryName": {
|
||||||
|
"message": "Bridge"
|
||||||
|
}
|
||||||
|
, "optionsBridgeCategoryDescription": {
|
||||||
|
"message": "Native bridge application."
|
||||||
|
}
|
||||||
|
, "optionsBridgeLoading": {
|
||||||
|
"message": "Loading bridge info..."
|
||||||
|
}
|
||||||
|
, "optionsBridgeMissing": {
|
||||||
|
"message": "Bridge application not found. Try downloading and installing the latest version."
|
||||||
|
}
|
||||||
|
, "optionsBridgeInfo": {
|
||||||
|
"message": "Bridge info:"
|
||||||
|
}
|
||||||
|
, "optionsBridgeStatusCompatible": {
|
||||||
|
"message": "STATUS: COMPATIBLE"
|
||||||
|
}
|
||||||
|
, "optionsBridgeStatusIncompatible": {
|
||||||
|
"message": "STATUS: INCOMPATIBLE"
|
||||||
|
}
|
||||||
|
, "optionsBridgeOlder": {
|
||||||
|
"message": "Bridge version older than expected, try updating bridge to the latest bridge version."
|
||||||
|
}
|
||||||
|
, "optionsBridgeNewer": {
|
||||||
|
"message": "Bridge version newer than expected, try updating extension to the latest bridge version."
|
||||||
|
}
|
||||||
|
|
||||||
, "optionsMediaCategoryName": {
|
, "optionsMediaCategoryName": {
|
||||||
"message": "Media casting"
|
"message": "Media casting"
|
||||||
}
|
}
|
||||||
|
|||||||
37
ext/src/lib/getBridgeInfo.js
Normal file
37
ext/src/lib/getBridgeInfo.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import semver from "semver";
|
||||||
|
|
||||||
|
export default async function getBridgeInfo () {
|
||||||
|
let applicationVersion;
|
||||||
|
try {
|
||||||
|
const response = await browser.runtime.sendNativeMessage(
|
||||||
|
APPLICATION_NAME
|
||||||
|
, { subject: "bridge:getInfo"
|
||||||
|
, data: EXTENSION_VERSION });
|
||||||
|
|
||||||
|
applicationVersion = response.data;
|
||||||
|
} catch (err) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare installed bridge version to the version the
|
||||||
|
* extension was built alongside and is known to be
|
||||||
|
* compatible with.
|
||||||
|
*
|
||||||
|
* TODO: Determine compatibility with semver and enforce/notify
|
||||||
|
* user.
|
||||||
|
*/
|
||||||
|
if (applicationVersion !== APPLICATION_VERSION) {
|
||||||
|
console.error(`Expecting ${APPLICATION_NAME} v${APPLICATION_VERSION}, found v${applicationVersion}.`
|
||||||
|
, semver.lt(applicationVersion, APPLICATION_VERSION)
|
||||||
|
? "Try updating the native app to the latest version."
|
||||||
|
: "Try updating the extension to the latest version");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: applicationVersion
|
||||||
|
, isVersionCompatible: applicationVersion === APPLICATION_VERSION
|
||||||
|
, isVersionOlder: semver.lt(applicationVersion, APPLICATION_VERSION)
|
||||||
|
, isVersionNewer: semver.gt(applicationVersion, APPLICATION_VERSION)
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -340,12 +340,6 @@ function initBridge (tabId, frameId) {
|
|||||||
bridgeMap.set(tabId, port);
|
bridgeMap.set(tabId, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start version handoff
|
|
||||||
port.postMessage({
|
|
||||||
subject: "bridge:initialize"
|
|
||||||
, data: EXTENSION_VERSION
|
|
||||||
});
|
|
||||||
|
|
||||||
port.onDisconnect.addListener(p => {
|
port.onDisconnect.addListener(p => {
|
||||||
if (p.error) {
|
if (p.error) {
|
||||||
console.error(`${APPLICATION_NAME} disconnected:`, p.error.message);
|
console.error(`${APPLICATION_NAME} disconnected:`, p.error.message);
|
||||||
@@ -431,27 +425,6 @@ messageRouter.register("main", async (message, sender) => {
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
case "main:bridgeInitialized": {
|
|
||||||
const applicationVersion = message.data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare installed bridge version to the version the
|
|
||||||
* extension was built alongside and is known to be
|
|
||||||
* compatible with.
|
|
||||||
*
|
|
||||||
* TODO: Determine compatibility with semver and enforce/notify
|
|
||||||
* user.
|
|
||||||
*/
|
|
||||||
if (applicationVersion !== APPLICATION_VERSION) {
|
|
||||||
console.error(`Expecting ${APPLICATION_NAME} v${APPLICATION_VERSION}, found v${applicationVersion}.`
|
|
||||||
, semver.lt(applicationVersion, APPLICATION_VERSION)
|
|
||||||
? "Try updating the native app to the latest version."
|
|
||||||
: "Try updating the extension to the latest version");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
case "main:openPopup": {
|
case "main:openPopup": {
|
||||||
await openPopup(tabId);
|
await openPopup(tabId);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import ReactDOM from "react-dom";
|
|||||||
import defaultOptions from "./defaultOptions";
|
import defaultOptions from "./defaultOptions";
|
||||||
import EditableList from "./EditableList";
|
import EditableList from "./EditableList";
|
||||||
|
|
||||||
|
import getBridgeInfo from "../lib/getBridgeInfo";
|
||||||
|
|
||||||
|
|
||||||
const _ = browser.i18n.getMessage;
|
const _ = browser.i18n.getMessage;
|
||||||
|
|
||||||
@@ -41,6 +43,8 @@ class App extends Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
options: props.options
|
options: props.options
|
||||||
|
, bridgeInfo: null
|
||||||
|
, bridgeLoading: true
|
||||||
, isFormValid: true
|
, isFormValid: true
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,6 +58,14 @@ class App extends Component {
|
|||||||
= this.getWhitelistItemPatternError.bind(this);
|
= this.getWhitelistItemPatternError.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async componentDidMount () {
|
||||||
|
const bridgeInfo = await getBridgeInfo();
|
||||||
|
this.setState({
|
||||||
|
bridgeInfo
|
||||||
|
, bridgeLoading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set stored option values to current state
|
* Set stored option values to current state
|
||||||
*/
|
*/
|
||||||
@@ -126,140 +138,199 @@ class App extends Component {
|
|||||||
return _("optionsUserAgentWhitelistInvalidMatchPattern", info);
|
return _("optionsUserAgentWhitelistInvalidMatchPattern", info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateBridgeInfo () {
|
||||||
|
this.setState({
|
||||||
|
bridgeLoading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const bridgeInfo = await getBridgeInfo();
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
bridgeInfo
|
||||||
|
, bridgeLoading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<form id="form" ref={ form => { this.form = form; }}
|
<div>
|
||||||
onSubmit={ this.handleFormSubmit }
|
<form id="form" ref={ form => { this.form = form; }}
|
||||||
onChange={ this.handleFormChange }>
|
onSubmit={ this.handleFormSubmit }
|
||||||
<fieldset className="category">
|
onChange={ this.handleFormChange }>
|
||||||
<legend className="category__name">
|
|
||||||
{ _("optionsMediaCategoryName") }
|
|
||||||
</legend>
|
|
||||||
<p className="category__description">
|
|
||||||
{ _("optionsMediaCategoryDescription") }
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<label className="option option--inline">
|
<fieldset className="category">
|
||||||
<input name="mediaEnabled"
|
|
||||||
type="checkbox"
|
|
||||||
checked={ this.state.options.mediaEnabled }
|
|
||||||
onChange={ this.handleInputChange } />
|
|
||||||
<div className="option__label">
|
|
||||||
{ _("optionsMediaEnabled") }
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<fieldset className="category"
|
|
||||||
disabled={ !this.state.options.mediaEnabled }>
|
|
||||||
<legend className="category__name">
|
<legend className="category__name">
|
||||||
{ _("optionsLocalMediaCategoryName") }
|
{ _("optionsMediaCategoryName") }
|
||||||
</legend>
|
</legend>
|
||||||
<p className="category__description">
|
<p className="category__description">
|
||||||
{ _("optionsLocalMediaCategoryDescription") }
|
{ _("optionsMediaCategoryDescription") }
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<input name="localMediaEnabled"
|
<input name="mediaEnabled"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={ this.state.options.localMediaEnabled }
|
checked={ this.state.options.mediaEnabled }
|
||||||
onChange={ this.handleInputChange } />
|
onChange={ this.handleInputChange } />
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsLocalMediaEnabled") }
|
{ _("optionsMediaEnabled") }
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<fieldset className="category"
|
||||||
|
disabled={ !this.state.options.mediaEnabled }>
|
||||||
|
<legend className="category__name">
|
||||||
|
{ _("optionsLocalMediaCategoryName") }
|
||||||
|
</legend>
|
||||||
|
<p className="category__description">
|
||||||
|
{ _("optionsLocalMediaCategoryDescription") }
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<label className="option option--inline">
|
||||||
|
<input name="localMediaEnabled"
|
||||||
|
type="checkbox"
|
||||||
|
checked={ this.state.options.localMediaEnabled }
|
||||||
|
onChange={ this.handleInputChange } />
|
||||||
|
<div className="option__label">
|
||||||
|
{ _("optionsLocalMediaEnabled") }
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label className="option">
|
||||||
|
<div className="option__label">
|
||||||
|
{ _("optionsLocalMediaServerPort") }
|
||||||
|
</div>
|
||||||
|
<input name="localMediaServerPort"
|
||||||
|
type="number"
|
||||||
|
required
|
||||||
|
min="1025"
|
||||||
|
max="65535"
|
||||||
|
value={ this.state.options.localMediaServerPort }
|
||||||
|
onChange={ this.handleInputChange } />
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset className="category">
|
||||||
|
<legend className="category__name">
|
||||||
|
{ _("optionsMirroringCategoryName") }
|
||||||
|
</legend>
|
||||||
|
<p className="category__description">
|
||||||
|
{ _("optionsMirroringCategoryDescription") }
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<label className="option option--inline">
|
||||||
|
<input name="mirroringEnabled"
|
||||||
|
type="checkbox"
|
||||||
|
checked={ this.state.options.mirroringEnabled }
|
||||||
|
onChange={ this.handleInputChange } />
|
||||||
|
<div className="option__label">
|
||||||
|
{ _("optionsMirroringEnabled") }
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="option">
|
<label className="option">
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsLocalMediaServerPort") }
|
{ _("optionsMirroringAppId") }
|
||||||
</div>
|
</div>
|
||||||
<input name="localMediaServerPort"
|
<input name="mirroringAppId"
|
||||||
type="number"
|
type="text"
|
||||||
required
|
required
|
||||||
min="1025"
|
value={ this.state.options.mirroringAppId }
|
||||||
max="65535"
|
|
||||||
value={ this.state.options.localMediaServerPort }
|
|
||||||
onChange={ this.handleInputChange } />
|
onChange={ this.handleInputChange } />
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset className="category">
|
<fieldset className="category">
|
||||||
<legend className="category__name">
|
<legend className="category__name">
|
||||||
{ _("optionsMirroringCategoryName") }
|
{ _("optionsUserAgentWhitelistCategoryName") }
|
||||||
</legend>
|
</legend>
|
||||||
<p className="category__description">
|
<p className="category__description">
|
||||||
{ _("optionsMirroringCategoryDescription") }
|
{ _("optionsUserAgentWhitelistCategoryDescription") }
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<input name="mirroringEnabled"
|
<input name="userAgentWhitelistEnabled"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={ this.state.options.mirroringEnabled }
|
checked={ this.state.options.userAgentWhitelistEnabled }
|
||||||
onChange={ this.handleInputChange } />
|
onChange={ this.handleInputChange } />
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsMirroringEnabled") }
|
{ _("optionsUserAgentWhitelistEnabled") }
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className="option">
|
||||||
|
<div className="option__label">
|
||||||
|
{ _("optionsUserAgentWhitelistContent") }
|
||||||
|
</div>
|
||||||
|
<EditableList data={ this.state.options.userAgentWhitelist }
|
||||||
|
onChange={ this.handleWhitelistChange }
|
||||||
|
itemPattern={ MATCH_PATTERN_REGEX }
|
||||||
|
itemPatternError={ this.getWhitelistItemPatternError }/>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</fieldset>
|
||||||
|
|
||||||
<label className="option">
|
<div id="buttons">
|
||||||
<div className="option__label">
|
<button onClick={ this.handleReset }>
|
||||||
{ _("optionsMirroringAppId") }
|
{ _("optionsReset") }
|
||||||
</div>
|
</button>
|
||||||
<input name="mirroringAppId"
|
<button type="submit"
|
||||||
type="text"
|
default
|
||||||
required
|
disabled={ !this.state.isFormValid }>
|
||||||
value={ this.state.options.mirroringAppId }
|
{ _("optionsSubmit") }
|
||||||
onChange={ this.handleInputChange } />
|
</button>
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset className="category">
|
|
||||||
<legend className="category__name">
|
|
||||||
{ _("optionsUserAgentWhitelistCategoryName") }
|
|
||||||
</legend>
|
|
||||||
<p className="category__description">
|
|
||||||
{ _("optionsUserAgentWhitelistCategoryDescription") }
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<label className="option option--inline">
|
|
||||||
<input name="userAgentWhitelistEnabled"
|
|
||||||
type="checkbox"
|
|
||||||
checked={ this.state.options.userAgentWhitelistEnabled }
|
|
||||||
onChange={ this.handleInputChange } />
|
|
||||||
<div className="option__label">
|
|
||||||
{ _("optionsUserAgentWhitelistEnabled") }
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div className="option">
|
|
||||||
<div className="option__label">
|
|
||||||
{ _("optionsUserAgentWhitelistContent") }
|
|
||||||
</div>
|
|
||||||
<EditableList data={ this.state.options.userAgentWhitelist }
|
|
||||||
onChange={ this.handleWhitelistChange }
|
|
||||||
itemPattern={ MATCH_PATTERN_REGEX }
|
|
||||||
itemPatternError={ this.getWhitelistItemPatternError }/>
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</form>
|
||||||
|
|
||||||
<div id="buttons">
|
<div className="bridge">
|
||||||
<button onClick={ this.handleReset }>
|
{ do {
|
||||||
{ _("optionsReset") }
|
if (this.state.bridgeLoading) {
|
||||||
</button>
|
<div className="bridge__loading">
|
||||||
<button type="submit"
|
{ _("optionsBridgeLoading") }
|
||||||
default
|
<progress></progress>
|
||||||
disabled={ !this.state.isFormValid }>
|
</div>
|
||||||
{ _("optionsSubmit") }
|
} else if (this.state.bridgeInfo) {
|
||||||
</button>
|
const bridgeInfo = this.state.bridgeInfo;
|
||||||
|
let debugInfo =
|
||||||
|
`${bridgeInfo.isVersionCompatible
|
||||||
|
? _("optionsBridgeStatusCompatible")
|
||||||
|
: _("optionsBridgeStatusIncompatible")}\n\n`
|
||||||
|
+ `${APPLICATION_NAME} v${bridgeInfo.version}\n`
|
||||||
|
+ `Expected: ${APPLICATION_VERSION}\n`
|
||||||
|
+ `Found: ${bridgeInfo.version}\n`;
|
||||||
|
|
||||||
|
if (bridgeInfo.isVersionOlder) {
|
||||||
|
debugInfo += `\n${_("optionsBridgeOlder")}`
|
||||||
|
}
|
||||||
|
if (bridgeInfo.isVersionNewer) {
|
||||||
|
debugInfo += `\n${_("optionsBridgeNewer")}`
|
||||||
|
}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{ _("optionsBridgeInfo") }
|
||||||
|
<div className="bridge__found">
|
||||||
|
<textarea className="bridge__info">{ debugInfo }</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
} else {
|
||||||
|
<div>
|
||||||
|
{ _("optionsBridgeInfo") }
|
||||||
|
<div className="bridge__missing">
|
||||||
|
{ _("optionsBridgeMissing") }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
browser.storage.sync.get("options").then(({options}) => {
|
(async () => {
|
||||||
|
const { options } = await browser.storage.sync.get("options");
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<App options={options} />
|
<App options={options} />
|
||||||
, document.querySelector("#root"));
|
, document.querySelector("#root"));
|
||||||
});
|
})()
|
||||||
|
|||||||
@@ -17,6 +17,48 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bridge {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bridge,
|
||||||
|
.bridge__loading {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bridge__loading {
|
||||||
|
align-items: center;
|
||||||
|
align-self: center;
|
||||||
|
font-size: 1.25em;
|
||||||
|
font-weight: 300;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bridge__loading progress {
|
||||||
|
margin-top: 5px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bridge__missing {
|
||||||
|
background-color: #d70022;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: white;
|
||||||
|
padding: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bridge__found {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bridge__info {
|
||||||
|
height: 150px;
|
||||||
|
margin-inline-start: 5px;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.category {
|
.category {
|
||||||
border: initial;
|
border: initial;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -24,7 +66,7 @@
|
|||||||
grid-column-gap: 20px;
|
grid-column-gap: 20px;
|
||||||
grid-row-gap: 5px;
|
grid-row-gap: 5px;
|
||||||
margin: initial;
|
margin: initial;
|
||||||
padding: 15px 0;
|
padding: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category:disabled {
|
.category:disabled {
|
||||||
|
|||||||
Reference in New Issue
Block a user