From cc79f387fd47dbed487b8ac52609cd709bd3ba88 Mon Sep 17 00:00:00 2001 From: Max Goodhart Date: Tue, 30 Jun 2020 17:11:41 -0700 Subject: [PATCH] Add TOML configuration and reorganize param names --- README.md | 16 ++++++ example.config.toml | 32 +++++++++++ package-lock.json | 5 ++ package.json | 3 +- src/node/index.js | 132 ++++++++++++++++++++++++++------------------ 5 files changed, 132 insertions(+), 56 deletions(-) create mode 100644 example.config.toml diff --git a/README.md b/README.md index fa61d6f..28b96ac 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,22 @@ Under the hood, think of Streamwall as a specialized web browser for mosaicing v 3. Use the browser window to load or control streams. The initial list will be populated from https://woke.net/#streams 4. If you enter the same stream code in multiple cells, it will merge them together for a larger stream. +## Configuration + +Streamwall has a growing number of configuration options. To get a summary run: + +``` +npm start -- --help +``` + +For long-term installations, it's recommended to put your options into a configuration file. To use a config file, run: + +``` +npm start -- --config="../streamwall.json" +``` + +See `config.example.toml` for an example. + ## Hotkeys The following hotkeys are available with the "control" webpage focused: diff --git a/example.config.toml b/example.config.toml new file mode 100644 index 0000000..e8314fd --- /dev/null +++ b/example.config.toml @@ -0,0 +1,32 @@ +# Set the background color (useful for chroma-keying) +#background-color = "#0f0" + +[control] +# Address to serve control server from +address = "http://localhost:80" + +# Override hostname and port +#hostname = "localhost" +#port = 80 + +# Username and password +password = "woke" +username = "woke" + +[cert] +# SSL certificates (optional) +# If you specify an https:// URL for the "webserver" option, a certificate will be automatically generated and signed by Let's Encrypt. +# For this to work, Streamwall must be accessible from both ports 80 and 443. + +# Uncomment to obtain a real certificate (otherwise a testing cert will be generated) +#production = true + +# Email address to use when registering SSL certificate with Let's Encrypt +#email = "hi@streamwall.io" + +# Directory to store certificate +#dir = "../streamwall-cert" + +[streamdelay] +#endpoint = "http://localhost:8404" +#key = "super-secret" diff --git a/package-lock.json b/package-lock.json index f7f5e8e..3e22b2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1181,6 +1181,11 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, + "@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", diff --git a/package.json b/package.json index 09d1886..3eb20b6 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,13 @@ "scripts": { "build": "webpack", "start": "npm run build -- --display=errors-only && electron dist", - "start-local": "npm run build -- --display=errors-only && electron dist --webserver=http://localhost:4444 --username=woke --password=woke", + "start-local": "npm run build -- --display=errors-only && electron dist --control.address=http://localhost:4444 --control.username=woke --control.password=woke", "test": "jest" }, "author": "Max Goodhart ", "license": "MIT", "dependencies": { + "@iarna/toml": "^2.2.5", "ejs": "^3.1.3", "electron": "^9.0.4", "koa": "^2.12.1", diff --git a/src/node/index.js b/src/node/index.js index 071dd85..eef72eb 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -1,5 +1,6 @@ import fs from 'fs' import yargs from 'yargs' +import TOML from '@iarna/toml' import { app, shell, session, BrowserWindow } from 'electron' import { ensureValidURL } from '../util' @@ -8,59 +9,80 @@ import StreamWindow from './StreamWindow' import StreamdelayClient from './StreamdelayClient' import initWebServer from './server' -async function main() { - const argv = yargs +function parseArgs() { + return yargs .config('config', (configPath) => { - return JSON.parse(fs.readFileSync(configPath, 'utf-8')) - }) - .group( - ['webserver', 'cert-dir', 'cert-email', 'hostname', 'port'], - 'Web Server Configuration', - ) - .option('webserver', { - describe: 'Enable control webserver and specify the URL', - implies: ['username', 'password'], - }) - .option('hostname', { - describe: 'Override hostname the control server listens on', - }) - .option('port', { - describe: 'Override port the control server listens on', - number: true, - }) - .option('cert-dir', { - describe: 'Private directory to store SSL certificate in', - implies: ['email'], - }) - .option('cert-production', { - describe: 'Obtain a real SSL certificate using production servers', - }) - .option('email', { - describe: 'Email for owner of SSL certificate', - }) - .option('username', { - describe: 'Web control server username', - }) - .option('password', { - describe: 'Web control server password', - }) - .option('open', { - describe: 'After launching, open the control website in a browser', - boolean: true, - default: true, + return TOML.parse(fs.readFileSync(configPath, 'utf-8')) }) .option('background-color', { describe: 'Background color of wall (useful for chroma-keying)', default: '#000', }) - .option('streamdelay-endpoint', { + .group( + [ + 'control.username', + 'control.password', + 'control.address', + 'control.hostname', + 'control.port', + 'control.open', + ], + 'Control Webserver', + ) + .option('control.username', { + describe: 'Web control server username', + }) + .option('control.password', { + describe: 'Web control server password', + }) + .option('control.open', { + describe: 'After launching, open the control website in a browser', + boolean: true, + default: true, + }) + .option('control.address', { + describe: 'Enable control webserver and specify the URL', + implies: ['control.username', 'control.password'], + }) + .option('control.hostname', { + describe: 'Override hostname the control server listens on', + }) + .option('control.port', { + describe: 'Override port the control server listens on', + number: true, + }) + .group( + ['cert.dir', 'cert.production', 'cert.email'], + 'Automatic SSL Certificate', + ) + .option('cert.dir', { + describe: 'Private directory to store SSL certificate in', + implies: ['email'], + default: null, + }) + .option('cert.production', { + describe: 'Obtain a real SSL certificate using production servers', + }) + .option('cert.email', { + describe: 'Email for owner of SSL certificate', + }) + .group(['streamdelay.endpoint', 'streamdelay.key'], 'Streamdelay') + .option('streamdelay.endpoint', { describe: 'URL of Streamdelay endpoint', default: 'http://localhost:8404', }) - .option('streamdelay-key', { + .option('streamdelay.key', { describe: 'Streamdelay API key', + default: null, }) .help().argv +} + +async function main() { + const argv = parseArgs() + if (argv.help) { + return + } // Reject all permission requests from web content. session @@ -132,28 +154,28 @@ async function main() { } } - if (argv.webserver) { + if (argv.control.address) { ;({ broadcastState } = await initWebServer({ - certDir: argv.certDir, - certProduction: argv.certProduction, - email: argv.email, - url: argv.webserver, - hostname: argv.hostname, - port: argv.port, - username: argv.username, - password: argv.password, + certDir: argv.cert.dir, + certProduction: argv.cert.production, + email: argv.cert.email, + url: argv.control.address, + hostname: argv.control.hostname, + port: argv.control.port, + username: argv.control.username, + password: argv.control.password, getInitialState, onMessage, })) - if (argv.open) { - shell.openExternal(argv.webserver) + if (argv.control.open) { + shell.openExternal(argv.control.address) } } - if (argv.streamdelayKey) { + if (argv.streamdelay.key) { streamdelayClient = new StreamdelayClient({ - endpoint: argv.streamdelayEndpoint, - key: argv.streamdelayKey, + endpoint: argv.streamdelay.endpoint, + key: argv.streamdelay.key, }) streamdelayClient.on('state', (state) => { clientState.streamdelay = state