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.

138 lines
4.3 KiB

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
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. w = require("wodge"),
  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. var usage =
  15. "usage: \n\
  16. $ ws [--directory|-d <dir>] [--port|-p <port>] [--log-format|-f dev|default|short|tiny] [--compress|-c]\n\
  17. $ ws --config\n\
  18. $ ws --help|-h";
  19. function halt(message){
  20. dope.red.log("Error: %s", message);
  21. dope.log(usage);
  22. process.exit(1);
  23. }
  24. /* Merge together options from
  25. - ~/.local-web-server.json
  26. - {cwd}/.local-web-server.json
  27. - {cwd}/package.json
  28. */
  29. var storedConfig = loadConfig(
  30. path.join(w.getHomeDir(), ".local-web-server.json"),
  31. path.join(process.cwd(), ".local-web-server.json"),
  32. path.join(process.cwd(), "package.json:local-web-server")
  33. );
  34. /* override stored config with values parsed from command line */
  35. try {
  36. var argv = cliArgs([
  37. { name: "port", alias: "p", type: Number, defaultOption: true, value: 8000 },
  38. { name: "log-format", alias: "f", type: String },
  39. { name: "help", alias: "h", type: Boolean },
  40. { name: "directory", alias: "d", type: String, value: process.cwd() },
  41. { name: "config", type: Boolean },
  42. { name: "compress", alias: "c", type: Boolean }
  43. ]).parse();
  44. } catch(err){
  45. halt(err.message);
  46. }
  47. argv = w.extend(storedConfig, argv);
  48. if (argv.config){
  49. dope.log("Stored config: ");
  50. dope.log(storedConfig);
  51. process.exit(0);
  52. } else if (argv.help){
  53. dope.log(usage);
  54. } else {
  55. var total = {
  56. req: 0,
  57. bytes: 0,
  58. connections: 0
  59. };
  60. process.on("SIGINT", function(){
  61. dope.showCursor();
  62. dope.log();
  63. process.exit(0);
  64. });
  65. /* customised logger :date token, purely to satisfy Logstalgia. */
  66. morgan.token("date", function(){
  67. var a = new Date();
  68. return (a.getDate() + "/" + a.getUTCMonth() + "/" + a.getFullYear() + ":" + a.toTimeString())
  69. .replace("GMT", "").replace(" (BST)", "");
  70. });
  71. var app = connect();
  72. /* log using --log-format (if supplied), else output statics */
  73. if(argv["log-format"]){
  74. app.use(morgan(argv["log-format"]));
  75. } else {
  76. app.use(function(req, res, next){
  77. dope.column(1).write(++total.req);
  78. next();
  79. });
  80. }
  81. /* --compress enables compression */
  82. if (argv.compress) app.use(compress());
  83. /* static file server including directory browsing support */
  84. app.use(serveStatic(path.resolve(argv.directory)))
  85. .use(directory(path.resolve(argv.directory), { icons: true }));
  86. /* launch server */
  87. var server = http.createServer(app)
  88. .on("error", function(err){
  89. if (err.code === "EADDRINUSE"){
  90. halt("port " + argv.port + " is already is use");
  91. } else {
  92. halt(err.message);
  93. }
  94. })
  95. .listen(argv.port);
  96. /* write status to stderr so stdout can be piped to disk ($ ws > log.txt) */
  97. if (path.resolve(argv.directory) === process.cwd()){
  98. dope.error("serving at %underline{%s}", "http://localhost:" + argv.port);
  99. } else {
  100. dope.error("serving %underline{%s} at %underline{%s}", argv.directory, "http://localhost:" + argv.port);
  101. }
  102. /* in stats mode, monitor connections and bytes transferred */
  103. if (!argv["log-format"]){
  104. dope.hideCursor();
  105. dope.log("%underline{Requests} %underline{Data} %underline{Connections}");
  106. server.on("connection", function(socket){
  107. var oldWrite = socket.write;
  108. socket.write = function(data) {
  109. if (!Buffer.isBuffer(data)) {
  110. data = new Buffer(data);
  111. }
  112. oldWrite.call(this, data);
  113. total.bytes += data.length;
  114. dope.column(12).write(w.padRight(w.bytesToSize(total.bytes, 2), 12));
  115. };
  116. dope.column(24).write(++total.connections);
  117. socket.on("close", function(){
  118. dope.column(24).write(w.padRight(--total.connections));
  119. });
  120. });
  121. }
  122. }