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

View File

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