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.

127 lines
4.0 KiB

11 years ago
11 years ago
11 years ago
11 years ago
12 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. #!/usr/bin/env node
  2. "use strict";
  3. var dope = require("console-dope"),
  4. connect = require("connect"),
  5. http = require("http"),
  6. cliArgs = require("command-line-args"),
  7. o = require("object-tools"),
  8. path = require("path"),
  9. loadConfig = require("config-master"),
  10. morgan = require("morgan"),
  11. serveStatic = require("serve-static"),
  12. directory = require("serve-index"),
  13. compress = require("compression"),
  14. homePath = require("home-path"),
  15. logStats = require("stream-log-stats");
  16. var usage =
  17. "usage: \n\
  18. $ ws [--directory|-d <dir>] [--port|-p <port>] [--log-format|-f node|dev|default|short|tiny|logstalgia] [--compress|-c]\n\
  19. $ ws --config\n\
  20. $ ws --help|-h";
  21. function halt(message){
  22. dope.red.log("Error: %s", message);
  23. dope.log(usage);
  24. process.exit(1);
  25. }
  26. /* Load and merge together options from
  27. - ~/.local-web-server.json
  28. - {cwd}/.local-web-server.json
  29. - the `local-web-server` property of {cwd}/package.json
  30. */
  31. var storedConfig = loadConfig(
  32. path.join(homePath(), ".local-web-server.json"),
  33. path.join(process.cwd(), ".local-web-server.json"),
  34. { jsonPath: path.join(process.cwd(), "package.json"), configProperty: "local-web-server" }
  35. );
  36. /* parse command line args */
  37. try {
  38. var argv = cliArgs([
  39. { name: "port", alias: "p", type: Number, defaultOption: true },
  40. { name: "log-format", alias: "f", type: String },
  41. { name: "help", alias: "h", type: Boolean },
  42. { name: "directory", alias: "d", type: String },
  43. { name: "config", type: Boolean },
  44. { name: "compress", alias: "c", type: Boolean },
  45. { name: "refreshRate", alias: "r", type: Number }
  46. ]).parse();
  47. } catch(err){
  48. halt(err.message);
  49. }
  50. /* override built-in defaults with stored config then command line args */
  51. argv = o.extend({
  52. port: 8000,
  53. directory: process.cwd(),
  54. refreshRate: 500
  55. }, storedConfig, argv);
  56. if (argv.config){
  57. dope.log("Stored config: ");
  58. dope.log(storedConfig);
  59. process.exit(0);
  60. } else if (argv.help){
  61. dope.log(usage);
  62. } else {
  63. process.on("SIGINT", function(){
  64. dope.showCursor();
  65. dope.log();
  66. process.exit(0);
  67. });
  68. var app = connect();
  69. /* log using --log-format (if supplied) */
  70. if(argv["log-format"]) {
  71. if (argv["log-format"] === "none"){
  72. // do nothing, no logging required
  73. } else {
  74. if (argv["log-format"] === "logstalgia"){
  75. /* customised logger :date token, purely to satisfy Logstalgia. */
  76. morgan.token("date", function(){
  77. var a = new Date();
  78. return (a.getDate() + "/" + a.getUTCMonth() + "/" + a.getFullYear() + ":" + a.toTimeString())
  79. .replace("GMT", "").replace(" (BST)", "");
  80. });
  81. argv["log-format"] = "default";
  82. }
  83. app.use(morgan(argv["log-format"]));
  84. }
  85. /* if no specific `--log-format` required, pipe the default web log output
  86. into `log-stats`, which prints statistics to the console */
  87. } else {
  88. app.use(morgan({ stream: logStats({ refreshRate: argv.refreshRate }) }));
  89. }
  90. /* --compress enables compression */
  91. if (argv.compress) app.use(compress());
  92. /* static file server including directory browsing support */
  93. app.use(serveStatic(path.resolve(argv.directory)))
  94. .use(directory(path.resolve(argv.directory), { icons: true }));
  95. /* launch server */
  96. http.createServer(app)
  97. .on("error", function(err){
  98. if (err.code === "EADDRINUSE"){
  99. halt("port " + argv.port + " is already is use");
  100. } else {
  101. halt(err.message);
  102. }
  103. })
  104. .listen(argv.port);
  105. /* write status to stderr (stdout is reserved for web log output) */
  106. if (path.resolve(argv.directory) === process.cwd()){
  107. dope.error("serving at %underline{%s}", "http://localhost:" + argv.port);
  108. } else {
  109. dope.error("serving %underline{%s} at %underline{%s}", argv.directory, "http://localhost:" + argv.port);
  110. }
  111. }