diff --git a/index.js b/index.js new file mode 100644 index 0000000..e212190 --- /dev/null +++ b/index.js @@ -0,0 +1,142 @@ +const fs = require("fs"); +const path = require("path"); +const readline = require("readline/promises"); +const integration = require("./src/integration"); +const hardware = require("./src/hardware"); +const webview = require("./src/webview"); +const { app } = require("electron"); + +/** + * This promise resolves when the app has finished initializing, + * allowing to safely create browser windows and perform other + * initialization tasks. + */ +app.whenReady().then(async () => { + let args = parseArgs(process); + let argsProvided = !!Object.keys(args).length; + + let argsFilePath = path.join(app.getPath("userData"), "Arguments.json"); + let argsFileExists = fs.existsSync(argsFilePath); + + // Setup arguments from file path + if ("setup" in args || (!argsProvided && !argsFileExists)) { + await sleep(3000); + do { + args = await promptArgs(process); + } while (!Object.keys(args).length); + fs.writeFileSync(argsFilePath, JSON.stringify(args, null, 2)); + } else if (!argsProvided && argsFileExists) { + args = JSON.parse(fs.readFileSync(argsFilePath)); + } + console.log(JSON.stringify(args, null, 2)); + + // Chained init functions + const chained = [webview.init, hardware.init, integration.init]; + for (const init of chained) { + if (!(await init(args))) { + break; + } + } +}); + +/** + * Parses command-line arguments from the given process object. + * + * @param {Object} proc - The process object. + * @returns {Object} An object mapping argument names to their corresponding values. + */ +const parseArgs = (proc) => { + let args = {}; + proc.argv.slice(1).forEach((arg) => { + if (arg !== ".") { + const [key, value] = arg.split("="); + args[key.replace("--", "").replace("-", "_")] = value; + } + }); + return args; +}; + +/** + * Prompts argument values on the command-line. + * + * @param {Object} proc - The process object. + * @returns {Object} An object mapping argument names to their corresponding values. + */ +const promptArgs = async (proc) => { + const read = readline.createInterface({ + input: proc.stdin, + output: proc.stdout, + }); + + // Array of arguments + const arguments = [ + { + key: "web_url", + question: "\nEnter WEB url", + fallback: "http://192.168.1.42:8123", + }, + { + key: "web_theme", + question: "Enter WEB theme", + fallback: "dark", + }, + { + key: "web_zoom", + question: "Enter WEB zoom level", + fallback: "1.25", + }, + { + key: "mqtt_url", + question: "\nEnter MQTT url", + fallback: "mqtt://192.168.1.42:1883", + }, + { + key: "mqtt_user", + question: "Enter MQTT username", + fallback: "kiosk", + }, + { + key: "mqtt_password", + question: "Enter MQTT password", + fallback: "password", + }, + { + key: "mqtt_discovery", + question: "Enter MQTT discovery prefix", + fallback: "homeassistant", + }, + { + key: "check", + question: "\nEverything looks good?", + fallback: "yes", + }, + ]; + + // Prompt each argument and wait for the answer + let args = {}; + for (const { key, question, fallback } of arguments) { + if (key === "check") { + const json = JSON.stringify(args, null, 2); + const prompt = `${question}\n${json}\n(${fallback}): `; + const answer = (await read.question(prompt)).trim() || fallback; + if (!["y", "yes"].includes(answer)) { + args = {}; + } + } else { + const prompt = `${question} (${fallback}): `; + const answer = (await read.question(prompt)).trim() || fallback; + args[key] = answer; + } + } + read.close(); + + return args; +}; + +/** + * Helper function for asynchronous sleep. + * + * @param {number} ms - Sleep time in milliseconds. + * @returns {Promise} A promise resolving after the timeout. + */ +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); diff --git a/main.js b/main.js deleted file mode 100644 index 52c1ca4..0000000 --- a/main.js +++ /dev/null @@ -1,35 +0,0 @@ -const integration = require("./src/integration"); -const hardware = require("./src/hardware"); -const webview = require("./src/webview"); -const { app } = require("electron"); - -/** - * This promise resolves when the app has finished initializing, - * allowing to safely create browser windows and perform other - * initialization tasks. - */ -app.whenReady().then(() => { - const args = parseArgs(process); - webview.init(args) && hardware.init(args) && integration.init(args); -}); - -/** - * Parses command-line arguments from the given process object. - * - * @param {Object} proc - The process object. - * @returns {Object} An object mapping argument names to their corresponding values. - */ -const parseArgs = (proc) => { - let argv = proc.argv.slice(1).join(" ").trim(); - if (argv.length && argv[0] == ".") { - argv = argv.slice(1); - } - argv = argv.replace(/--|=/g, " ").replace(/\s+/g, " "); - argv = argv.trim().split(" "); - argv = argv.reduce( - (args, k, i, v) => - i % 2 ? args : { ...args, [k.replace("-", "_")]: v[i + 1] }, - {} - ); - return argv; -}; diff --git a/package.json b/package.json index ac4c045..c975ecc 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "author": "leukipp", "version": "0.0.1", "license": "MIT", - "main": "main.js", + "main": "index.js", "scripts": { "start": "electron . --web-url=https://demo.home-assistant.io", "build": "electron-forge make" @@ -26,8 +26,11 @@ "name": "@electron-forge/maker-deb", "config": { "options": { + "productName": "TouchKio", "icon": "img/icon.png", - "category": "Network" + "categories": [ + "Network" + ] } } } diff --git a/yarn.lock b/yarn.lock index 4947e36..97bf50e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -246,9 +246,9 @@ optionalDependencies: global-agent "^3.0.0" -"@electron/node-gyp@git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2": +"@electron/node-gyp@https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2": version "10.2.0-electron.1" - resolved "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2" + resolved "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2" dependencies: env-paths "^2.2.0" exponential-backoff "^3.1.1"