Add lib/options module for typed/easier options storage access

This commit is contained in:
hensm
2019-05-17 14:53:43 +01:00
parent a97e14cb31
commit 964f54a06b
4 changed files with 93 additions and 57 deletions

View File

@@ -10,10 +10,13 @@ export interface Options {
mirroringAppId: string;
userAgentWhitelistEnabled: boolean;
userAgentWhitelist: string[];
[key: string]: Options[keyof Options];
}
const options: Options = {
mediaEnabled: true
bridgeApplicationName: APPLICATION_NAME
, mediaEnabled: true
, mediaSyncElement: false
, mediaStopOnUnload: false
, localMediaEnabled: true

54
ext/src/lib/options.ts Normal file
View File

@@ -0,0 +1,54 @@
"use strict";
import { Options } from "../defaultOptions";
/**
* Fetches `options` key from storage and returns it as
* Options interface type.
*/
async function getAll (): Promise<Options> {
const { options }: { options: Options } =
await browser.storage.sync.get("options");
return options;
}
/**
* Takes Options object and sets to `options` storage key.
* Returns storage promise.
*/
async function setAll (options: Options): Promise<void> {
return browser.storage.sync.set({ options });
}
/**
* Gets specific option from storage and returns it as its
* type from Options interface type.
*/
async function get<T extends keyof Options> (name: T): Promise<Options[T]> {
const options = await getAll();
if (options.hasOwnProperty(name)) {
return options[name];
}
}
/**
* Sets specific option to storage. Returns storage
* promise.
*/
async function set<T extends keyof Options> (
name: T
, value: Options[T]): Promise<void> {
const options = await getAll();
options[name] = value;
return setAll(options);
}
export default {
get, getAll
, set, setAll
}

View File

@@ -5,6 +5,7 @@ import semver from "semver";
import defaultOptions, { Options } from "./defaultOptions";
import getBridgeInfo from "./lib/getBridgeInfo";
import messageRouter from "./lib/messageRouter";
import options from "./lib/options";
import nativeMessaging from "./lib/nativeMessaging";
import { getChromeUserAgent } from "./lib/userAgents";
@@ -29,17 +30,13 @@ browser.runtime.onInstalled.addListener(async details => {
switch (details.reason) {
// Set default options
case "install": {
await browser.storage.sync.set({
options: defaultOptions
});
await options.setAll(defaultOptions);
break;
}
// Set newly added options
case "update": {
const { options: existingOptions }
= await browser.storage.sync.get("options");
const existingOptions = await options.getAll();
const newOptions: Partial<Options> = {};
// Find options not already in storage
@@ -50,11 +47,9 @@ browser.runtime.onInstalled.addListener(async details => {
}
// Update storage with default values of new options
await browser.storage.sync.set({
options: {
...existingOptions
, ...newOptions
}
options.setAll({
...existingOptions
, ...newOptions
});
break;
@@ -87,17 +82,17 @@ const mediaCastTargetUrlPatterns = new Set([
const LOCAL_MEDIA_URL_PATTERN = "file://*/*";
async function createMenus () {
const { options } = await browser.storage.sync.get("options");
const opts = await options.getAll();
/**
* If options aren't set or menus have already been
* created, return.
*/
if (!options || mirrorCastMenuId || mediaCastMenuId) {
if (!opts || mirrorCastMenuId || mediaCastMenuId) {
return;
}
if (options.localMediaEnabled) {
if (opts.localMediaEnabled) {
mediaCastTargetUrlPatterns.add(LOCAL_MEDIA_URL_PATTERN);
}
@@ -107,7 +102,7 @@ async function createMenus () {
, id: "contextCastMedia"
, targetUrlPatterns: Array.from(mediaCastTargetUrlPatterns)
, title: _("contextCast")
, visible: options.mediaEnabled
, visible: opts.mediaEnabled
});
// Screen/Tab mirroring "Cast..." context menu item
@@ -115,7 +110,7 @@ async function createMenus () {
contexts: [ "browser_action", "page", "tools_menu" ]
, id: "contextCast"
, title: _("contextCast")
, visible: options.mirroringEnabled
, visible: opts.mirroringEnabled
// Mirroring doesn't work from local files
, documentUrlPatterns: [
@@ -317,7 +312,6 @@ let currentUAString: string;
async function onBeforeSendHeaders (
details: { requestHeaders?: browser.webRequest.HttpHeaders }) {
const { options } = await browser.storage.sync.get("options");
const { os } = await browser.runtime.getPlatformInfo();
// Create Chrome UA from platform info on first run
@@ -353,10 +347,10 @@ async function onBeforeSendHeaders (
* Updates any extension state based on options changes.
*/
async function onOptionsUpdated (alteredOptions?: Array<(keyof Options)>) {
const { options } = await browser.storage.sync.get("options");
const opts = await options.getAll();
// If options aren't set yet, return
if (!options) {
if (!opts) {
return;
}
@@ -367,8 +361,8 @@ async function onOptionsUpdated (alteredOptions?: Array<(keyof Options)>) {
function register_userAgentWhitelist () {
browser.webRequest.onBeforeSendHeaders.addListener(
onBeforeSendHeaders
, { urls: options.userAgentWhitelistEnabled
? options.userAgentWhitelist
, { urls: opts.userAgentWhitelistEnabled
? opts.userAgentWhitelist
: [] }
, [ "blocking", "requestHeaders" ]);
}
@@ -394,18 +388,18 @@ async function onOptionsUpdated (alteredOptions?: Array<(keyof Options)>) {
if (alteredOptions.includes("mirroringEnabled")) {
browser.menus.update(mirrorCastMenuId, {
visible: options.mirroringEnabled
visible: opts.mirroringEnabled
});
}
if (alteredOptions.includes("mediaEnabled")) {
browser.menus.update(mediaCastMenuId, {
visible: options.mediaEnabled
visible: opts.mediaEnabled
});
}
if (alteredOptions.includes("localMediaEnabled")) {
if (options.localMediaEnabled) {
if (opts.localMediaEnabled) {
mediaCastTargetUrlPatterns.add(LOCAL_MEDIA_URL_PATTERN);
} else {
mediaCastTargetUrlPatterns.delete(LOCAL_MEDIA_URL_PATTERN);
@@ -448,7 +442,7 @@ browser.menus.onClicked.addListener(async (info, tab) => {
|| info.menuItemId === mediaCastMenuId) {
const { frameId } = info;
const { options } = await browser.storage.sync.get("options");
const mirroringAppId = await options.get("mirroringAppId");
// Load cast setup script
await browser.tabs.executeScript(tab.id, {
@@ -466,7 +460,7 @@ browser.menus.onClicked.addListener(async (info, tab) => {
var selectedMedia = ${info.pageUrl
? ReceiverSelectorMediaType.Tab
: ReceiverSelectorMediaType.Screen};
var FX_CAST_RECEIVER_APP_ID = "${options.mirroringAppId}";
var FX_CAST_RECEIVER_APP_ID = "${mirroringAppId}";
`
, frameId
});
@@ -513,16 +507,13 @@ browser.menus.onClicked.addListener(async (info, tab) => {
if (info.parentMenuItemId === whitelistMenuId) {
const matchPattern = whitelistMenuMap.get(info.menuItemId);
const options: Options =
(await browser.storage.sync.get("options")).options;
const userAgentWhitelist = await options.get("userAgentWhitelist");
// Add to whitelist
options.userAgentWhitelist.push(matchPattern);
userAgentWhitelist.push(matchPattern);
// Update options
await browser.storage.sync.set({
options
});
await options.set("userAgentWhitelist", userAgentWhitelist)
}
});

View File

@@ -10,6 +10,7 @@ import Bridge from "./Bridge";
import EditableList from "./EditableList";
import getBridgeInfo, { BridgeInfo } from "../../lib/getBridgeInfo";
import options from "../../lib/options";
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/utils";
@@ -77,11 +78,9 @@ class OptionsApp extends Component<{}, OptionsAppState> {
}
public async componentDidMount () {
const { options } = await browser.storage.sync.get("options");
this.setState({
hasLoaded: true
, options
, options: await options.getAll()
});
const bridgeInfo = await getBridgeInfo();
@@ -259,14 +258,6 @@ class OptionsApp extends Component<{}, OptionsAppState> {
);
}
/**
* Set stored option values to current state
*/
private setStorage () {
return browser.storage.sync.set({
options: this.state.options
});
}
private handleReset () {
this.setState({
@@ -280,15 +271,12 @@ class OptionsApp extends Component<{}, OptionsAppState> {
this.form.reportValidity();
try {
const { options: oldOptions }
= await browser.storage.sync.get("options");
await this.setStorage();
const { options } = await browser.storage.sync.get("options");
const oldOpts = await options.getAll();
await options.setAll(this.state.options);
const alteredOptions = [];
for (const [ key, val ] of Object.entries(options)) {
const oldVal = oldOptions[key];
for (const [ key, val ] of Object.entries(this.state.options)) {
const oldVal = oldOpts[key];
if (oldVal !== val) {
alteredOptions.push(key);
}
@@ -325,16 +313,16 @@ class OptionsApp extends Component<{}, OptionsAppState> {
private handleInputChange (ev: React.ChangeEvent<HTMLInputElement>) {
const { target } = ev;
this.setState(({ options }) => {
options[target.name as keyof Options] = getInputValue(target);
return { options };
this.setState(currentState => {
currentState.options[target.name] = getInputValue(target);
return currentState;
});
}
private handleWhitelistChange (whitelist: string[]) {
this.setState(({ options }) => {
options.userAgentWhitelist = whitelist;
return { options };
this.setState(currentState => {
currentState.options.userAgentWhitelist = whitelist;
return currentState;
});
}