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.

187 lines
5.1 KiB

9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 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('local-web-server-default-stack')
  9. /**
  10. * @module local-web-server
  11. */
  12. const tool = new CommandLineTool()
  13. /**
  14. * @alias module:local-web-server
  15. * @extends module:middleware-stack
  16. */
  17. class LocalWebServer {
  18. constructor (stack) {
  19. const commandLineArgs = require('command-line-args')
  20. const commandLineUsage = require('command-line-usage')
  21. const cli = require('../lib/cli-data')
  22. let stackPath
  23. const stackIndex = process.argv.indexOf('--stack')
  24. if (stackIndex > -1) {
  25. stackPath = process.argv[stackIndex + 1]
  26. if (/^-/.test(stackPath)) stackPath = null
  27. }
  28. const stackModule = loadStack(stackPath) || DefaultStack
  29. this.stack = new stackModule()
  30. this.stack.addAll()
  31. const middlewareOptionDefinitions = this.stack.getOptionDefinitions()
  32. // console.log(middlewareOptionDefinitions)
  33. const usage = commandLineUsage(cli.usage(middlewareOptionDefinitions))
  34. let options = {}
  35. try {
  36. options = commandLineArgs(cli.optionDefinitions.concat(middlewareOptionDefinitions))
  37. } catch (err) {
  38. console.error(usage)
  39. tool.halt(err)
  40. }
  41. const loadConfig = require('config-master')
  42. const stored = loadConfig('local-web-server')
  43. /* override stored config with command line options */
  44. options = Object.assign(stored, options.server, options.middleware, options.misc)
  45. this.options = options
  46. if (options.verbose) {
  47. // debug.setLevel(1)
  48. }
  49. if (options.config) {
  50. tool.stop(JSON.stringify(options, null, ' '), 0)
  51. } else if (options.version) {
  52. const pkg = require(path.resolve(__dirname, '..', 'package.json'))
  53. tool.stop(pkg.version)
  54. } else {
  55. if (this.options.help) {
  56. tool.stop(usage)
  57. }
  58. }
  59. }
  60. getApplication (options) {
  61. const Koa = require('koa')
  62. const app = new Koa()
  63. app.use(this.stack.compose(this.options))
  64. return app
  65. }
  66. getServer (options) {
  67. const app = this.getApplication(options)
  68. options = this.options
  69. let key = options.key
  70. let cert = options.cert
  71. app.on('error', err => {
  72. if (options['log-format']) {
  73. console.error(ansi.format(err.stack, 'red'))
  74. }
  75. })
  76. if (options.https) {
  77. key = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.key')
  78. cert = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.crt')
  79. }
  80. let server = null
  81. if (key && cert) {
  82. const fs = require('fs')
  83. const serverOptions = {
  84. key: fs.readFileSync(key),
  85. cert: fs.readFileSync(cert)
  86. }
  87. const https = require('https')
  88. server = https.createServer(serverOptions, app.callback())
  89. server.isHttps = true
  90. } else {
  91. const http = require('http')
  92. server = http.createServer(app.callback())
  93. }
  94. return server
  95. }
  96. listen (options, callback) {
  97. options = this.options
  98. const server = this.getServer()
  99. const port = options.port || 8000
  100. server.listen(port, () => {
  101. onServerUp(port, options.directory, server.isHttps)
  102. if (callback) callback()
  103. })
  104. return server
  105. }
  106. }
  107. function onServerUp (port, directory, isHttps) {
  108. const ipList = getIPList()
  109. .map(iface => `[underline]{${isHttps ? 'https' : 'http'}://${iface.address}:${port}}`)
  110. .join(', ')
  111. console.error(ansi.format(
  112. path.resolve(directory || '') === process.cwd()
  113. ? `serving at ${ipList}`
  114. : `serving [underline]{${directory}} at ${ipList}`
  115. ))
  116. }
  117. function getIPList () {
  118. const flatten = require('reduce-flatten')
  119. const os = require('os')
  120. let ipList = Object.keys(os.networkInterfaces())
  121. .map(key => os.networkInterfaces()[key])
  122. .reduce(flatten, [])
  123. .filter(iface => iface.family === 'IPv4')
  124. ipList.unshift({ address: os.hostname() })
  125. return ipList
  126. }
  127. /**
  128. * Return default, stored and command-line options combined
  129. */
  130. function collectUserOptions (mwOptionDefinitions) {
  131. const loadConfig = require('config-master')
  132. const stored = loadConfig('local-web-server')
  133. const cli = require('../lib/cli-data')
  134. /* parse command line args */
  135. const definitions = mwOptionDefinitions
  136. ? cli.optionDefinitions.concat(arrayify(mwOptionDefinitions))
  137. : cli.optionDefinitions
  138. let cliOptions = tool.getOptions(definitions, cli.usage(definitions))
  139. /* override stored config with command line options */
  140. const options = Object.assign(stored, cliOptions.server, cliOptions.middleware, cliOptions.misc)
  141. return options
  142. }
  143. function loadStack (modulePath) {
  144. let module
  145. if (modulePath) {
  146. const fs = require('fs')
  147. try {
  148. module = require(path.resolve(modulePath))
  149. if (!module.prototype.addAll) {
  150. tool.halt(new Error('Must supply a MiddlewareStack'))
  151. }
  152. } catch (err) {
  153. const walkBack = require('walk-back')
  154. const foundPath = walkBack(path.resolve(process.cwd(), 'node_modules'), modulePath)
  155. if (foundPath) {
  156. module = require(foundPath)
  157. }
  158. }
  159. }
  160. return module
  161. }
  162. module.exports = LocalWebServer