You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
3.8 KiB

8 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
  1. #!/usr/bin/env node
  2. 'use strict'
  3. const ansi = require('ansi-escape-sequences')
  4. const path = require('path')
  5. const arrayify = require('array-back')
  6. const t = require('typical')
  7. const CommandLineTool = require('command-line-tool')
  8. const DefaultStack = require('./default-stack')
  9. const debug = require('./debug')
  10. /**
  11. * @module local-web-server
  12. */
  13. const tool = new CommandLineTool()
  14. /**
  15. * @alias module:local-web-server
  16. * @extends module:middleware-stack
  17. */
  18. class LocalWebServer {
  19. constructor (stack) {
  20. this.stack = stack || new DefaultStack()
  21. this.stack.addAll()
  22. }
  23. _init (options) {
  24. this.options = this.options || Object.assign(options || {}, collectUserOptions(this.stack.getOptionDefinitions()))
  25. }
  26. addStack (stack) {
  27. this.stack = stack
  28. }
  29. getApplication (options) {
  30. this._init(options)
  31. const Koa = require('koa')
  32. const app = new Koa()
  33. app.use(this.stack.compose(this.options))
  34. return app
  35. }
  36. getServer (options) {
  37. const app = this.getApplication(options)
  38. options = this.options
  39. let key = options.key
  40. let cert = options.cert
  41. app.on('error', err => {
  42. if (options['log-format']) {
  43. console.error(ansi.format(err.stack, 'red'))
  44. }
  45. })
  46. if (options.https) {
  47. key = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.key')
  48. cert = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.crt')
  49. }
  50. let server = null
  51. if (key && cert) {
  52. const fs = require('fs')
  53. const serverOptions = {
  54. key: fs.readFileSync(key),
  55. cert: fs.readFileSync(cert)
  56. }
  57. const https = require('https')
  58. server = https.createServer(serverOptions, app.callback())
  59. server.isHttps = true
  60. } else {
  61. const http = require('http')
  62. server = http.createServer(app.callback())
  63. }
  64. return server
  65. }
  66. listen (options, callback) {
  67. this._init(options)
  68. options = this.options
  69. if (options.verbose) {
  70. debug.setLevel(1)
  71. }
  72. if (options.config) {
  73. tool.stop(JSON.stringify(options, null, ' '), 0)
  74. } else if (options.version) {
  75. const pkg = require(path.resolve(__dirname, '..', 'package.json'))
  76. tool.stop(pkg.version)
  77. } else {
  78. const server = this.getServer()
  79. const port = options.port || 8000
  80. server.listen(port, () => {
  81. onServerUp(port, options.directory, server.isHttps)
  82. if (callback) callback()
  83. })
  84. return server
  85. }
  86. }
  87. }
  88. function onServerUp (port, directory, isHttps) {
  89. const ipList = getIPList()
  90. .map(iface => `[underline]{${isHttps ? 'https' : 'http'}://${iface.address}:${port}}`)
  91. .join(', ')
  92. console.error(ansi.format(
  93. path.resolve(directory || '') === process.cwd()
  94. ? `serving at ${ipList}`
  95. : `serving [underline]{${directory}} at ${ipList}`
  96. ))
  97. }
  98. function getIPList () {
  99. const flatten = require('reduce-flatten')
  100. const os = require('os')
  101. let ipList = Object.keys(os.networkInterfaces())
  102. .map(key => os.networkInterfaces()[key])
  103. .reduce(flatten, [])
  104. .filter(iface => iface.family === 'IPv4')
  105. ipList.unshift({ address: os.hostname() })
  106. return ipList
  107. }
  108. /**
  109. * Return default, stored and command-line options combined
  110. */
  111. function collectUserOptions (mwOptionDefinitions) {
  112. const loadConfig = require('config-master')
  113. const stored = loadConfig('local-web-server')
  114. const cli = require('../lib/cli-data')
  115. /* parse command line args */
  116. const definitions = cli.optionDefinitions.concat(arrayify(mwOptionDefinitions))
  117. let cliOptions = tool.getOptions(definitions, cli.usage(definitions))
  118. /* override stored config with command line options */
  119. const options = Object.assign(stored, cliOptions.server, cliOptions.middleware, cliOptions.misc)
  120. // console.error(require('util').inspect(options, { depth: 3, colors: true }))
  121. return options
  122. }
  123. module.exports = LocalWebServer