Browse Source

server now created on contruction, before views intantiated.. refactor view API

master
Lloyd Brookes 9 years ago
parent
commit
9d3484fed6
  1. 3
      bin/cli.js
  2. 18
      doc/api.md
  3. 2
      doc/visualisation.md
  4. 59
      lib/cli-view.js
  5. 111
      lib/local-web-server.js
  6. 12
      test/test.js

3
bin/cli.js

@ -1,5 +1,4 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict' 'use strict'
const LocalWebServer = require('../') const LocalWebServer = require('../')
const ws = new LocalWebServer()
ws.getServer()
new LocalWebServer()

18
doc/api.md

@ -5,10 +5,10 @@
* [LocalWebServer](#exp_module_local-web-server--LocalWebServer) ⇐ <code>module:middleware-stack</code> * [LocalWebServer](#exp_module_local-web-server--LocalWebServer) ⇐ <code>module:middleware-stack</code>
* [new LocalWebServer([options])](#new_module_local-web-server--LocalWebServer_new) * [new LocalWebServer([options])](#new_module_local-web-server--LocalWebServer_new)
* _instance_ * _instance_
* [.view](#module_local-web-server--LocalWebServer.LocalWebServer+view) : <code>View</code>
* [.features](#module_local-web-server--LocalWebServer.LocalWebServer+features) : <code>Array.&lt;Feature&gt;</code> * [.features](#module_local-web-server--LocalWebServer.LocalWebServer+features) : <code>Array.&lt;Feature&gt;</code>
* [.options](#module_local-web-server--LocalWebServer.LocalWebServer+options) : <code>object</code> * [.options](#module_local-web-server--LocalWebServer.LocalWebServer+options) : <code>object</code>
* [.server](#module_local-web-server--LocalWebServer+server) : <code>Server</code>
* [.view](#module_local-web-server--LocalWebServer.LocalWebServer+view) : <code>View</code>
* [.server](#module_local-web-server--LocalWebServer.LocalWebServer+server) : <code>Server</code>
* [.getApplication()](#module_local-web-server--LocalWebServer+getApplication) ⇒ <code>function</code> * [.getApplication()](#module_local-web-server--LocalWebServer+getApplication) ⇒ <code>function</code>
* [.getServer()](#module_local-web-server--LocalWebServer+getServer) ⇒ <code>Server</code> * [.getServer()](#module_local-web-server--LocalWebServer+getServer) ⇒ <code>Server</code>
* _inner_ * _inner_
@ -28,12 +28,6 @@
- .port} <code>number</code> - Port - .port} <code>number</code> - Port
- .stack} <code>Array.&lt;string&gt;</code> | <code>Array.&lt;Features&gt;</code> - Port - .stack} <code>Array.&lt;string&gt;</code> | <code>Array.&lt;Features&gt;</code> - Port
<a name="module_local-web-server--LocalWebServer.LocalWebServer+view"></a>
#### localWebServer.view : <code>View</code>
Current view.
**Kind**: instance property of <code>[LocalWebServer](#exp_module_local-web-server--LocalWebServer)</code>
<a name="module_local-web-server--LocalWebServer.LocalWebServer+features"></a> <a name="module_local-web-server--LocalWebServer.LocalWebServer+features"></a>
#### localWebServer.features : <code>Array.&lt;Feature&gt;</code> #### localWebServer.features : <code>Array.&lt;Feature&gt;</code>
@ -46,7 +40,13 @@ Loaded feature modules
Config Config
**Kind**: instance property of <code>[LocalWebServer](#exp_module_local-web-server--LocalWebServer)</code> **Kind**: instance property of <code>[LocalWebServer](#exp_module_local-web-server--LocalWebServer)</code>
<a name="module_local-web-server--LocalWebServer+server"></a>
<a name="module_local-web-server--LocalWebServer.LocalWebServer+view"></a>
#### localWebServer.view : <code>View</code>
Current view.
**Kind**: instance property of <code>[LocalWebServer](#exp_module_local-web-server--LocalWebServer)</code>
<a name="module_local-web-server--LocalWebServer.LocalWebServer+server"></a>
#### localWebServer.server : <code>Server</code> #### localWebServer.server : <code>Server</code>
Node.js server Node.js server

2
doc/visualisation.md

@ -13,7 +13,7 @@ Then, start the server, outputting `combined` format logs to disk:
$ ws -f combined > web.log $ ws -f combined > web.log
``` ```
In a separate tab, point goaccess at `web.log` and it will display statistics in real time:
In a separate terminal, point goaccess at `web.log` and it will display statistics in real time:
``` ```
$ goaccess -p ~/.goaccessrc -f web.log $ goaccess -p ~/.goaccessrc -f web.log

59
lib/cli-view.js

@ -1,31 +1,48 @@
'use strict'
class CliView { class CliView {
constructor (localWebServer) { constructor (localWebServer) {
this.options = localWebServer.options
this.localWebServer = localWebServer
} }
info (key, value) {
if (key && value) {
write (msg) {
const writeToStdout = [ 'log', 'info' ]
Object.keys(msg).forEach(key => {
if (writeToStdout.includes(key)) {
console.log(msg[key])
} else if (key === 'config' && msg.config && this.localWebServer.options.verbose) {
printLine(msg.config)
} else if (key === 'error') {
const ansi = require('ansi-escape-sequences')
console.error(ansi.format(msg.error, 'red'))
}
})
}
}
module.exports = CliView
function printLine (config) {
const output = objectToTable(config)
process.stderr.write(output)
}
function objectToTable (object) {
const ansi = require('ansi-escape-sequences') const ansi = require('ansi-escape-sequences')
const tableLayout = require('table-layout') const tableLayout = require('table-layout')
const output = tableLayout({ key: ansi.format(key, 'bold'), value: value}, {
const t = require('typical')
const data = Object.keys(object).map(key => {
if (t.isObject(object[key])) {
return { key: ansi.format(key, 'bold'), value: objectToTable(object[key]) }
} else {
return { key: ansi.format(key, 'bold'), value: object[key] }
}
})
return tableLayout(data, {
padding: { left: '', right: ' ' }, padding: { left: '', right: ' ' },
columns: [ columns: [
{ name: 'key', width: 18 },
{ name: 'value', nowrap: true }
// { name: 'key', width: 18 },
// { name: 'value', nowrap: true }
] ]
}) })
process.stderr.write(output)
} else {
console.error(key)
}
}
verbose (key, value) {
if (this.options.verbose) {
this.info(key, value)
}
}
error (msg) {
console.error(ansi.format(msg, 'red'))
}
} }
module.exports = CliView

111
lib/local-web-server.js

@ -22,17 +22,10 @@ class LocalWebServer {
*/ */
constructor (initOptions) { constructor (initOptions) {
initOptions = initOptions || {} initOptions = initOptions || {}
const commandLineArgs = require('command-line-args')
const commandLineUsage = require('command-line-usage') const commandLineUsage = require('command-line-usage')
const CliView = require('./cli-view') const CliView = require('./cli-view')
const cli = require('../lib/cli-data') const cli = require('../lib/cli-data')
/**
* Current view.
* @type {View}
*/
this.view = new CliView(this)
/* get stored config */ /* get stored config */
const loadConfig = require('config-master') const loadConfig = require('config-master')
const stored = loadConfig('local-web-server') const stored = loadConfig('local-web-server')
@ -47,35 +40,10 @@ class LocalWebServer {
this.features = this._buildFeatureStack(featurePaths) this.features = this._buildFeatureStack(featurePaths)
/* gather feature optionDefinitions and parse the command line */ /* gather feature optionDefinitions and parse the command line */
const featureOptionDefinitions = this.features
.filter(mw => mw.optionDefinitions)
.map(mw => mw.optionDefinitions())
.reduce(flatten, [])
.filter(def => def)
.map(def => {
def.group = 'middleware'
return def
})
const featureOptionDefinitions = gatherOptionDefinitions(this.features)
const usage = commandLineUsage(cli.usage(featureOptionDefinitions)) const usage = commandLineUsage(cli.usage(featureOptionDefinitions))
let options = {}
const allOptionDefinitions = cli.optionDefinitions.concat(featureOptionDefinitions) const allOptionDefinitions = cli.optionDefinitions.concat(featureOptionDefinitions)
if (!initOptions.testMode) {
try {
options = commandLineArgs(allOptionDefinitions)
} catch (err) {
this.view.error(err.toString())
if (err.name === 'DUPLICATE_NAME') {
this.view.error('\nOption Definitions:')
this.view.error(allOptionDefinitions.map(def => {
return `name: ${def.name}${def.alias ? ', alias: ' + def.alias : ''}`
}).join('\n'))
}
this.view.info(usage)
process.exit(1)
}
}
let options = initOptions.testMode ? {} : parseCommandLineOptions(allOptionDefinitions, this.view)
/* combine in stored config */ /* combine in stored config */
options = Object.assign( options = Object.assign(
@ -93,26 +61,41 @@ class LocalWebServer {
*/ */
this.options = options this.options = options
if (options.view) {
const View = loadModule(options.view)
this.view = new View(this)
}
/**
* Current view.
* @type {View}
*/
this.view = null
/* --config */ /* --config */
if (options.config) { if (options.config) {
this.view.info(JSON.stringify(options, null, ' '))
console.error(JSON.stringify(options, null, ' '))
process.exit(0) process.exit(0)
/* --version */ /* --version */
} else if (options.version) { } else if (options.version) {
const pkg = require(path.resolve(__dirname, '..', 'package.json')) const pkg = require(path.resolve(__dirname, '..', 'package.json'))
this.view.info(pkg.version)
console.error(pkg.version)
process.exit(0) process.exit(0)
/* --help */ /* --help */
} else if (options.help) { } else if (options.help) {
this.view.info(usage)
console.error(usage)
process.exit(0) process.exit(0)
} else {
/**
* Node.js server
* @type {Server}
*/
this.server = this.getServer()
if (options.view) {
const View = loadModule(options.view)
this.view = new View(this)
} else {
this.view = new CliView(this)
}
} }
} }
@ -144,7 +127,7 @@ class LocalWebServer {
* Returns a listening server which processes requests using the middleware supplied. * Returns a listening server which processes requests using the middleware supplied.
* @returns {Server} * @returns {Server}
*/ */
getServer (onListening) {
getServer () {
const app = this.getApplication() const app = this.getApplication()
const options = this.options const options = this.options
@ -173,21 +156,18 @@ class LocalWebServer {
} }
server.listen(options.port) server.listen(options.port)
if (onListening) server.on('listening', onListening)
// if (onListening) server.on('listening', onListening)
/* on server-up message */
if (!options.testMode) { if (!options.testMode) {
server.on('listening', () => { server.on('listening', () => {
const ipList = getIPList() const ipList = getIPList()
.map(iface => `[underline]{${server.isHttps ? 'https' : 'http'}://${iface.address}:${options.port}}`) .map(iface => `[underline]{${server.isHttps ? 'https' : 'http'}://${iface.address}:${options.port}}`)
.join(', ') .join(', ')
this.view.info('Serving at', ansi.format(ipList))
console.error('Serving at', ansi.format(ipList))
}) })
} }
/**
* Node.js server
* @type {Server}
*/
this.server = server
return server return server
} }
@ -234,7 +214,7 @@ function loadStack (modulePath) {
process.exit(1) process.exit(1)
} }
} else { } else {
const msg = `No module found at: \n${tried.join('\n')}`
const msg = `No module found for: ${modulePath}`
console.error(msg) console.error(msg)
process.exit(1) process.exit(1)
} }
@ -299,4 +279,35 @@ function parseFeaturePaths (configStack) {
return featurePaths return featurePaths
} }
function gatherOptionDefinitions (features) {
return features
.filter(mw => mw.optionDefinitions)
.map(mw => mw.optionDefinitions())
.reduce(flatten, [])
.filter(def => def)
.map(def => {
def.group = 'middleware'
return def
})
}
function parseCommandLineOptions (allOptionDefinitions) {
const commandLineArgs = require('command-line-args')
try {
return commandLineArgs(allOptionDefinitions)
} catch (err) {
console.error(err)
/* handle duplicate option names */
if (err.name === 'DUPLICATE_NAME') {
console.error('\nOption Definitions:')
console.error(allOptionDefinitions.map(def => {
return `name: ${def.name}${def.alias ? ', alias: ' + def.alias : ''}`
}).join('\n'))
}
console.error(usage)
process.exit(1)
}
}
module.exports = LocalWebServer module.exports = LocalWebServer

12
test/test.js

@ -12,13 +12,13 @@ test('stack', function (t) {
port: 8100, port: 8100,
testMode: true testMode: true
}) })
const server = ws.getServer(() => {
ws.server.on('listening', () => {
return request('http://localhost:8100/') return request('http://localhost:8100/')
.then(c.checkResponse(t, 200, /1234512345/)) .then(c.checkResponse(t, 200, /1234512345/))
.then(server.close.bind(server))
.then(ws.server.close.bind(ws.server))
.catch(err => { .catch(err => {
t.fail(err.message) t.fail(err.message)
server.close()
ws.server.close()
}) })
}) })
}) })
@ -34,13 +34,13 @@ test('https', function (t) {
const url = require('url') const url = require('url')
const reqOptions = url.parse('https://localhost:8100/') const reqOptions = url.parse('https://localhost:8100/')
reqOptions.rejectUnauthorized = false reqOptions.rejectUnauthorized = false
const server = ws.getServer(() => {
ws.server.on('listening', () => {
return request(reqOptions) return request(reqOptions)
.then(c.checkResponse(t, 200, /1234512345/)) .then(c.checkResponse(t, 200, /1234512345/))
.then(server.close.bind(server))
.then(ws.server.close.bind(ws.server))
.catch(err => { .catch(err => {
t.fail(err.message) t.fail(err.message)
server.close()
ws.server.close()
}) })
}) })
}) })
Loading…
Cancel
Save