diff --git a/package.json b/package.json index 3e131a9c..7e084ffe 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "connect": "^3.7.0", "crypto-js": "^4.0.0", "highlight.js": "^11.0.0", + "js-yaml": "^4.1.0", "npm-run-all": "^4.1.5", "prismjs": "^1.23.0", "register-service-worker": "^1.6.2", diff --git a/server.js b/server.js index 27c4edb0..d08fc26a 100644 --- a/server.js +++ b/server.js @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ +/* This is a simple Node.js http server, that is used to serve up the contents of ./dist */ const connect = require('connect'); const serveStatic = require('serve-static'); @@ -12,28 +14,19 @@ const isDocker = !!process.env.IS_DOCKER; /* Checks env var for port. If undefined, will use Port 80 for Docker, or 4000 for metal */ const port = process.env.PORT || isDocker ? 80 : 4000; -/* eslint no-console: 0 */ -const printWelcomeMessage = () => { - getLocalIp().then(({ address }) => { - const ip = address || 'localhost'; - console.log(overComplicatedMessage(ip, port)); - }); -} - const getLocalIp = () => { const dnsLookup = util.promisify(dns.lookup); return dnsLookup(os.hostname()); -} +}; -const overComplicatedMessage = (ip, port) => { +const overComplicatedMessage = (ip) => { let msg = ''; const chars = { RESET: '\x1b[0m', CYAN: '\x1b[36m', GREEN: '\x1b[32m', BLUE: '\x1b[34m', - UNDERLINE: '\033[4m', - BOLD: '\033[1m', + BRIGHT: '\x1b[1m', BR: '\n', }; const stars = (count) => new Array(count).fill('*').join(''); @@ -42,32 +35,39 @@ const overComplicatedMessage = (ip, port) => { if (isDocker) { const containerId = process.env.HOSTNAME || undefined; msg = `${chars.BLUE}${stars(91)}${chars.BR}${chars.RESET}` - + `${chars.CYAN}${chars.BOLD}Welcome to Dashy! 🚀${chars.RESET}${chars.BR}` + + `${chars.CYAN}Welcome to Dashy! 🚀${chars.RESET}${chars.BR}` + `${chars.GREEN}Your new dashboard is now up and running ` + `${containerId ? `in container ID ${containerId}` : 'with Docker'}${chars.BR}` + `${chars.GREEN}After updating your config file, run ` - + `'${chars.UNDERLINE}docker exec -it ${containerId || '[container-id]'} yarn build` + + `'${chars.BRIGHT}docker exec -it ${containerId || '[container-id]'} yarn build` + `${chars.RESET}${chars.GREEN}' to rebuild${chars.BR}` + `${chars.BLUE}${stars(91)}${chars.BR}${chars.RESET}`; } else { msg = `${chars.GREEN}┏${line(75)}┓${chars.BR}` - + `┃ ${chars.CYAN}${chars.BOLD}Welcome to Dashy! 🚀${blanks(55)}${chars.GREEN}┃${chars.BR}` - + `┃ ${chars.CYAN}Your new dashboard is now up and running at ${chars.UNDERLINE}` + + `┃ ${chars.CYAN}Welcome to Dashy! 🚀${blanks(55)}${chars.GREEN}┃${chars.BR}` + + `┃ ${chars.CYAN}Your new dashboard is now up and running at ${chars.BRIGHT}` + `http://${ip}:${port}${chars.RESET}${blanks(18 - ip.length)}${chars.GREEN}┃${chars.BR}` - + `┃ ${chars.CYAN}After updating your config file, run '${chars.UNDERLINE}yarn build` + + `┃ ${chars.CYAN}After updating your config file, run '${chars.BRIGHT}yarn build` + `${chars.RESET}${chars.CYAN}' to rebuild the app${blanks(6)}${chars.GREEN}┃${chars.BR}` + `┗${line(75)}┛${chars.BR}${chars.BR}`; } return msg; -} +}; + +/* eslint no-console: 0 */ +const printWelcomeMessage = () => { + getLocalIp().then(({ address }) => { + const ip = address || 'localhost'; + console.log(overComplicatedMessage(ip)); + }); +}; try { connect() .use(serveStatic(`${__dirname}/dist`)) .use(serveStatic(`${__dirname}/public`, { index: 'default.html' })) .listen(port, () => { - try { printWelcomeMessage(port); } - catch (e) { console.log('Dashy is Starting...'); } + try { printWelcomeMessage(); } catch (e) { console.log('Dashy is Starting...'); } }); } catch (error) { console.log('Sorry, an error occurred ', error); diff --git a/src/utils/ConfigValidator.js b/src/utils/ConfigValidator.js index c0c84554..41fd903b 100644 --- a/src/utils/ConfigValidator.js +++ b/src/utils/ConfigValidator.js @@ -1,58 +1,63 @@ -const Ajv = require('ajv'); -const yaml = require('js-yaml'); -const fs = require('fs'); - -const schema = require('./ConfigSchema.json'); - -const validatorOptions = { - strict: true, - allowUnionTypes: true, - allErrors: true, -}; - -const ajv = new Ajv(validatorOptions); - -/* Message printed when validation was successful */ -const successMsg = () => { - return '\x1b[1m\x1b[32m\033[1mNo issues found, your configuration is valid :)\x1b[0m\n'; -} - -/* Formats error message. ready for printing to the console */ -const errorMsg = (output) => { - const warningFont = '\033[1m\x1b[103m\x1b[34m'; - const line = `${warningFont}${new Array(42).fill('━').join('')}\x1b[0m`; - let msg = `\n${line}\n${warningFont} Warning: ${output.length} ` - + `issue${output.length > 1 ? 's' : ''} found in config file \x1b[0m\n${line}\n`; - output.forEach((details, index) => { - msg += `${'\033[1m\x1b[36m'}${index + 1}. ${details.keyword} ${details.message} ` - + `in ${'\033[4m'}${details.instancePath}\x1b[0m\n`; - }); - return msg; -}; - -/* Error message printed when the file could not be opened */ -const bigError = () => { - const formatting = '\033[31m\033[1m\033[47m'; - const line = `${formatting}${new Array(41).fill('━').join('')}\x1b[0m\n`; - const msg = `${formatting} Error, unable to find / open 'conf.yml' \x1b[0m\n`; - return `${line}${msg}${line}\n`; -} - -/* Start the validation */ -const validate = (config, schema) => { - console.log('\nChecking config file against schema...'); - const valid = ajv.validate(schema, config); - if (valid) { - console.log(successMsg()); - } else { - console.log(errorMsg(ajv.errors)); - } -} - -try { - const config = yaml.safeLoad(fs.readFileSync('./public/conf.yml', 'utf8')); - validate(config, schema); -} catch (e) { - console.log(bigError(), e); -} - +/* eslint-disable no-console */ +/* Script that validates the conf.yml file against Dashy's schema, and outputs any issues */ +const Ajv = require('ajv'); +const yaml = require('js-yaml'); +const fs = require('fs'); + +const schema = require('./ConfigSchema.json'); + +const validatorOptions = { + strict: true, + allowUnionTypes: true, + allErrors: true, +}; + +const ajv = new Ajv(validatorOptions); + +/* Message printed when validation was successful */ +const successMsg = () => '\x1b[1m\x1b[32mNo issues found, your configuration is valid :)\x1b[0m\n'; + +/* Formats error message. ready for printing to the console */ +const errorMsg = (output) => { + const warningFont = '\x1b[103m\x1b[34m'; + const line = `${warningFont}${new Array(42).fill('━').join('')}\x1b[0m`; + let msg = `\n${line}\n${warningFont} Warning: ${output.length} ` + + `issue${output.length > 1 ? 's' : ''} found in config file \x1b[0m\n${line}\n`; + output.forEach((details, index) => { + msg += `${'\x1b[36m'}${index + 1}. ${details.keyword} ${details.message} ` + + `in ${details.instancePath}\x1b[0m\n`; + }); + return msg; +}; + +/* Error message printed when the file could not be opened */ +const bigError = () => { + const formatting = '\x1b[30m\x1b[43m'; + const line = `${formatting}${new Array(38).fill('━').join('')}\x1b[0m\n`; + const msg = `${formatting} Error, unable to validate 'conf.yml' \x1b[0m\n`; + return `\n${line}${msg}${line}\n`; +}; + +/* Start the validation */ +const validate = (config) => { + console.log('\nChecking config file against schema...'); + const valid = ajv.validate(schema, config); + if (valid) { + console.log(successMsg()); + } else { + console.log(errorMsg(ajv.errors)); + } +}; + +try { + const config = yaml.load(fs.readFileSync('./public/conf.yml', 'utf8')); + validate(config); +} catch (e) { + console.log(bigError()); + console.log('Please ensure that your config file is present, ' + + 'has the correct access rights and is parsable. ' + + 'If this warning persists, it may be an issue with the ' + + 'validator function. Please raise an issue, and include the following stack trace:\n'); + console.warn('\x1b[33mStack Trace for ConfigValidators.js:\x1b[0m\n', e); + console.log('\n\n'); +}