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.

152 lines
3.8 KiB

11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. #!/usr/bin/env node
  2. 'use strict'
  3. const localWebServer = require('../')
  4. const cliOptions = require('../lib/cli-options')
  5. const commandLineArgs = require('command-line-args')
  6. const ansi = require('ansi-escape-sequences')
  7. const loadConfig = require('config-master')
  8. const path = require('path')
  9. const os = require('os')
  10. const arrayify = require('array-back')
  11. const t = require('typical')
  12. const flatten = require('reduce-flatten')
  13. const cli = commandLineArgs(cliOptions.definitions)
  14. const usage = cli.getUsage(cliOptions.usageData)
  15. const stored = loadConfig('local-web-server')
  16. let options
  17. let isHttps = false
  18. try {
  19. options = collectOptions()
  20. } catch (err) {
  21. stop([ `[red]{Error}: ${err.message}`, usage ], 1)
  22. return
  23. }
  24. if (options.misc.help) {
  25. stop(usage, 0)
  26. } else if (options.misc.config) {
  27. stop(JSON.stringify(options.server, null, ' '), 0)
  28. } else {
  29. const valid = validateOptions(options)
  30. if (!valid) {
  31. /* gracefully end the process */
  32. return
  33. }
  34. const app = localWebServer({
  35. static: {
  36. root: options.server.directory,
  37. options: {
  38. hidden: true
  39. }
  40. },
  41. serveIndex: {
  42. path: options.server.directory,
  43. options: {
  44. icons: true,
  45. hidden: true
  46. }
  47. },
  48. log: {
  49. format: options.server['log-format']
  50. },
  51. compress: options.server.compress,
  52. mime: options.server.mime,
  53. forbid: options.server.forbid,
  54. spa: options.server.spa,
  55. 'no-cache': options.server['no-cache'],
  56. rewrite: options.server.rewrite,
  57. verbose: options.server.verbose,
  58. mocks: options.server.mocks
  59. })
  60. if (options.server.https) {
  61. options.server.key = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.key')
  62. options.server.cert = path.resolve(__dirname, '..', 'ssl', '127.0.0.1.crt')
  63. }
  64. if (options.server.key && options.server.cert) {
  65. const https = require('https')
  66. const fs = require('fs')
  67. isHttps = true
  68. const serverOptions = {
  69. key: fs.readFileSync(options.server.key),
  70. cert: fs.readFileSync(options.server.cert)
  71. }
  72. const server = https.createServer(serverOptions, app.callback())
  73. server.listen(options.server.port, onServerUp)
  74. } else {
  75. app.listen(options.server.port, onServerUp)
  76. }
  77. }
  78. function stop (msgs, exitCode) {
  79. arrayify(msgs).forEach(msg => console.error(ansi.format(msg)))
  80. process.exitCode = exitCode
  81. }
  82. function onServerUp () {
  83. let ipList = Object.keys(os.networkInterfaces())
  84. .map(key => os.networkInterfaces()[key])
  85. .reduce(flatten, [])
  86. .filter(iface => iface.family === 'IPv4')
  87. ipList.unshift({ address: os.hostname() })
  88. ipList = ipList
  89. .map(iface => `[underline]{${isHttps ? 'https' : 'http'}://${iface.address}:${options.server.port}}`)
  90. .join(', ')
  91. console.error(ansi.format(
  92. path.resolve(options.server.directory) === process.cwd()
  93. ? `serving at ${ipList}`
  94. : `serving [underline]{${options.server.directory}} at ${ipList}`
  95. ))
  96. }
  97. function collectOptions () {
  98. let options = {}
  99. /* parse command line args */
  100. options = cli.parse()
  101. const builtIn = {
  102. port: 8000,
  103. directory: process.cwd(),
  104. forbid: [],
  105. rewrite: []
  106. }
  107. if (options.server.rewrite) {
  108. options.server.rewrite = parseRewriteRules(options.server.rewrite)
  109. }
  110. /* override built-in defaults with stored config and then command line args */
  111. options.server = Object.assign(builtIn, stored, options.server)
  112. return options
  113. }
  114. function parseRewriteRules (rules) {
  115. return rules && rules.map(rule => {
  116. const matches = rule.match(/(\S*)\s*->\s*(\S*)/)
  117. return {
  118. from: matches[1],
  119. to: matches[2]
  120. }
  121. })
  122. }
  123. function validateOptions (options) {
  124. let valid = true
  125. function invalid (msg) {
  126. return `[red underline]{Invalid:} [bold]{${msg}}`
  127. }
  128. if (!t.isNumber(options.server.port)) {
  129. stop([ invalid(`--port must be numeric`), usage ], 1)
  130. valid = false
  131. }
  132. return valid
  133. }