From 265fa899f54461c9dec0ef2e25a902122376aa7c Mon Sep 17 00:00:00 2001 From: John Furrow Date: Mon, 16 Oct 2017 22:59:20 -0700 Subject: [PATCH] Improve error handling for missing config and static assets. --- package.json | 4 +- server/bin/enforce-prerequisites.js | 44 +++++++++++++ server/bin/start.js | 12 ++++ server/bin/web-server.js | 92 ++++++++++++++++++++++++++++ server/bin/www | 95 ----------------------------- 5 files changed, 150 insertions(+), 97 deletions(-) create mode 100644 server/bin/enforce-prerequisites.js create mode 100644 server/bin/start.js create mode 100755 server/bin/web-server.js delete mode 100755 server/bin/www diff --git a/package.json b/package.json index 5ac9a6f4..a7d772ab 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "build-assets": "UPDATED_SCRIPT=build npm run deprecated-warning && npm run build", "lint": "eslint .", "deprecated-warning": "node client/scripts/deprecated-warning.js && sleep 10", - "start:development:server": "NODE_ENV=development nodemon server/bin/www", + "start:development:server": "NODE_ENV=development nodemon server/bin/start.js", "start:development": "UPDATED_SCRIPT=start:development:server npm run deprecated-warning && npm run start:development:server", "start:production": "UPDATED_SCRIPT=start npm run deprecated-warning && npm start", - "start": "node server/bin/www", + "start": "node server/bin/start.js", "start:watch": "UPDATED_SCRIPT=start:development:client npm run deprecated-warning && npm run start:development:client", "start:development:client": "node client/scripts/start.js" }, diff --git a/server/bin/enforce-prerequisites.js b/server/bin/enforce-prerequisites.js new file mode 100644 index 00000000..b1e488b8 --- /dev/null +++ b/server/bin/enforce-prerequisites.js @@ -0,0 +1,44 @@ +'use strict'; +const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); +const fs = require('fs'); +const path = require('path'); + +const staticAssets = [ + path.join(__dirname, '../assets/index.html') +]; + +const configFiles = [ + path.join(__dirname, '../../config.js') +]; + +// Taken from react-scripts/check-required-files, but without console.logs. +const doFilesExist = files => { + let currentFilePath; + try { + files.forEach(filename => { + currentFilePath = filename; + fs.accessSync(filename, fs.F_OK); + }); + return true; + } catch (err) { + return false; + } +}; + +const enforcePrerequisites = () => { + return new Promise((resolve, reject) => { + if (!doFilesExist(configFiles)) { + reject(`Configuration files missing. Please check the 'Configuring' section of README.md.`); + return; + } + + if (!doFilesExist(staticAssets)) { + reject(`Static assets (index.html) are missing. Please check the 'Compiling assets and starting the server' section of README.md.`); + return; + } + + return resolve(); + }); +}; + +module.exports = enforcePrerequisites; \ No newline at end of file diff --git a/server/bin/start.js b/server/bin/start.js new file mode 100644 index 00000000..2883146c --- /dev/null +++ b/server/bin/start.js @@ -0,0 +1,12 @@ +'use strict'; +const chalk = require('chalk'); + +const enforcePrerequisites = require('./enforce-prerequisites'); +const {startWebServer} = require('./web-server'); + +enforcePrerequisites().then(startWebServer).catch((error) => { + console.log(chalk.red('Failed to start web server:')); + console.log(chalk.cyan(error)); + + process.exit(1); +}); \ No newline at end of file diff --git a/server/bin/web-server.js b/server/bin/web-server.js new file mode 100755 index 00000000..e006ea9e --- /dev/null +++ b/server/bin/web-server.js @@ -0,0 +1,92 @@ +'use strict'; + +const startWebServer = () => { + const chalk = require('chalk'); + const debug = require('debug')('flood:server'); + const fs = require('fs'); + + const app = require('../app'); + const config = require('../../config'); + + const port = normalizePort(config.floodServerPort); + const host = config.floodServerHost; + const useSSL = config.ssl; + + app.set('port', port); + app.set('host', host); + + // Create HTTP or HTTPS server. + let server; + + if (useSSL) { + if (!config.sslKey || !config.sslCert){ + console.error('Cannot start HTTPS server, `sslKey` or `sslCert`' + + ' is missing in config.js.'); + process.exit(1); + } + + server = require('spdy').createServer({ + key: fs.readFileSync(config.sslKey), + cert: fs.readFileSync(config.sslCert) + }, app); + } else { + server = require('http').createServer(app); + } + + // Listen on provided port, on all network interfaces. + server.listen(port, host); + server.on('error', onError); + server.on('listening', onListening); + + // Normalize a port into a number, string, or false. + function normalizePort(val) { + let port = parseInt(val, 10); + + // Named pipe. + if (isNaN(port)) { + return val; + } + + // Port number. + if (port >= 0) { + return port; + } + + return false; + } + + function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + let bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; + + // Handle specific listen errors with friendly messages. + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } + } + + // Event listener for HTTP server "listening" event. + function onListening() { + let addr = server.address(); + let bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; + debug('Listening on ' + bind); + } + + const address = chalk.underline(`${useSSL ? 'https' : 'http'}://${host}:${port}`); + + console.log(chalk.green(`Flood server starting on ${address}.\n`)); +}; + +module.exports = {startWebServer}; \ No newline at end of file diff --git a/server/bin/www b/server/bin/www deleted file mode 100755 index ec43568b..00000000 --- a/server/bin/www +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -const fs = require('fs'); - -// Ensure we have a user-defined config.js for use throughout the app. -try { - fs.accessSync(__dirname + '/../../config.js', fs.F_OK); -} catch (error) { - throw new Error('Cannot start Flood server, config.js is missing. Copy ' + - 'config.template.js to config.js.'); - process.exit(1); -} - -const app = require('../app'); -const config = require('../../config'); -const debug = require('debug')('flood:server'); - -const port = normalizePort(config.floodServerPort); -const host = config.floodServerHost; -const useSSL = config.ssl; - -app.set('port', port); -app.set('host', host); - -// Create HTTP or HTTPS server. -let server; - -if (useSSL) { - if (!config.sslKey || !config.sslCert){ - console.error('Cannot start HTTPS server, `sslKey` or `sslCert`' + - ' is missing in config.js.'); - process.exit(1); - } - - server = require('spdy').createServer({ - key: fs.readFileSync(config.sslKey), - cert: fs.readFileSync(config.sslCert) - }, app); -} else { - server = require('http').createServer(app); -} - -// Listen on provided port, on all network interfaces. -server.listen(port, host); -server.on('error', onError); -server.on('listening', onListening); - -// Normalize a port into a number, string, or false. -function normalizePort(val) { - let port = parseInt(val, 10); - - // Named pipe. - if (isNaN(port)) { - return val; - } - - // Port number. - if (port >= 0) { - return port; - } - - return false; -} - -function onError(error) { - if (error.syscall !== 'listen') { - throw error; - } - - let bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; - - // Handle specific listen errors with friendly messages. - switch (error.code) { - case 'EACCES': - console.error(bind + ' requires elevated privileges'); - process.exit(1); - break; - case 'EADDRINUSE': - console.error(bind + ' is already in use'); - process.exit(1); - break; - default: - throw error; - } -} - -// Event listener for HTTP server "listening" event. -function onListening() { - let addr = server.address(); - let bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; - debug('Listening on ' + bind); -} - -console.log(`\nFlood server starting on ${useSSL ? 'https' : 'http'}://${host}:${port}.\n`);