|
@ -4,9 +4,14 @@ var dope = require("console-dope"), |
|
|
connect = require("connect"), |
|
|
connect = require("connect"), |
|
|
http = require("http"), |
|
|
http = require("http"), |
|
|
fs = require("fs"), |
|
|
fs = require("fs"), |
|
|
Thing = require("nature").Thing, |
|
|
|
|
|
|
|
|
Model = require("nature").Model, |
|
|
w = require("wodge"), |
|
|
w = require("wodge"), |
|
|
path = require("path"); |
|
|
|
|
|
|
|
|
path = require("path"), |
|
|
|
|
|
loadConfig = require("config-master"), |
|
|
|
|
|
morgan = require("morgan"), |
|
|
|
|
|
serveStatic = require("serve-static"), |
|
|
|
|
|
directory = require('serve-index'), |
|
|
|
|
|
compress = require('compression'); |
|
|
|
|
|
|
|
|
var usage = "usage: ws [--directory|-d <directory>] [--port|-p <port>] [--log-format|-f dev|default|short|tiny] [--compress|-c]"; |
|
|
var usage = "usage: ws [--directory|-d <directory>] [--port|-p <port>] [--log-format|-f dev|default|short|tiny] [--compress|-c]"; |
|
|
|
|
|
|
|
@ -16,10 +21,8 @@ function halt(message){ |
|
|
process.exit(1); |
|
|
process.exit(1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
parse command-line args |
|
|
|
|
|
*/ |
|
|
|
|
|
var argv = new Thing() |
|
|
|
|
|
|
|
|
/* parse command-line args */ |
|
|
|
|
|
var argv = new Model() |
|
|
.define({ name: "port", alias: "p", type: "number", defaultOption: true, value: 8000 }) |
|
|
.define({ name: "port", alias: "p", type: "number", defaultOption: true, value: 8000 }) |
|
|
.define({ name: "log-format", alias: "f", type: "string" }) |
|
|
.define({ name: "log-format", alias: "f", type: "string" }) |
|
|
.define({ name: "help", alias: "h", type: "boolean" }) |
|
|
.define({ name: "help", alias: "h", type: "boolean" }) |
|
@ -29,35 +32,20 @@ var argv = new Thing() |
|
|
halt(err.message); |
|
|
halt(err.message); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
Set default options from "package.json", ".local-web-server.json" or "~/.local-web-server.json", in that order |
|
|
|
|
|
*/ |
|
|
|
|
|
var pkgPath = path.join(process.cwd(), "package.json"), |
|
|
|
|
|
lwsPath = path.join(process.cwd(), ".local-web-server.json"), |
|
|
|
|
|
homePath = path.join(w.getHomeDir(), ".local-web-server.json"); |
|
|
|
|
|
if (fs.existsSync(pkgPath)){ |
|
|
|
|
|
argv.set(require(pkgPath)["local-web-server"]); |
|
|
|
|
|
} |
|
|
|
|
|
if (fs.existsSync(lwsPath)){ |
|
|
|
|
|
argv.set(require(lwsPath)); |
|
|
|
|
|
} |
|
|
|
|
|
if (fs.existsSync(homePath)){ |
|
|
|
|
|
argv.set(require(homePath)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* Merge together options from "~/.local-web-server.json", "{cwd}/.local-web-server.json" and "{cwd}/package.json", in that order. */ |
|
|
|
|
|
var storedConfig = loadConfig( |
|
|
|
|
|
path.join(w.getHomeDir(), ".local-web-server.json"), |
|
|
|
|
|
path.join(process.cwd(), ".local-web-server.json"), |
|
|
|
|
|
path.join(process.cwd(), "package.json:local-web-server") |
|
|
|
|
|
); |
|
|
|
|
|
argv.set(storedConfig); |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
Finally, set the options from the command-line, overriding all defaults. |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* Finally, set the options from the command-line, overriding all defaults. */ |
|
|
argv.set(process.argv); |
|
|
argv.set(process.argv); |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
Die here if invalid args received |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* Die here if invalid args received */ |
|
|
if (!argv.valid) halt(argv.validationMessages); |
|
|
if (!argv.valid) halt(argv.validationMessages); |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
$ ws --help |
|
|
|
|
|
*/ |
|
|
|
|
|
if (argv.help){ |
|
|
if (argv.help){ |
|
|
dope.log(usage); |
|
|
dope.log(usage); |
|
|
|
|
|
|
|
@ -74,10 +62,8 @@ if (argv.help){ |
|
|
process.exit(0); |
|
|
process.exit(0); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
customised connect.logger :date token, purely to satisfy Logstalgia. |
|
|
|
|
|
*/ |
|
|
|
|
|
connect.logger.token("date", function(){ |
|
|
|
|
|
|
|
|
/* customised logger :date token, purely to satisfy Logstalgia. */ |
|
|
|
|
|
morgan.token("date", function(){ |
|
|
var a = new Date(); |
|
|
var a = new Date(); |
|
|
return (a.getDate() + "/" + a.getUTCMonth() + "/" + a.getFullYear() + ":" + a.toTimeString()) |
|
|
return (a.getDate() + "/" + a.getUTCMonth() + "/" + a.getFullYear() + ":" + a.toTimeString()) |
|
|
.replace("GMT", "").replace(" (BST)", ""); |
|
|
.replace("GMT", "").replace(" (BST)", ""); |
|
@ -85,11 +71,9 @@ if (argv.help){ |
|
|
|
|
|
|
|
|
var app = connect(); |
|
|
var app = connect(); |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
log using --log-format (if supplied), else output statics |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* log using --log-format (if supplied), else output statics */ |
|
|
if(argv["log-format"]){ |
|
|
if(argv["log-format"]){ |
|
|
app.use(connect.logger(argv["log-format"])); |
|
|
|
|
|
|
|
|
app.use(morgan(argv["log-format"])); |
|
|
} else { |
|
|
} else { |
|
|
app.use(function(req, res, next){ |
|
|
app.use(function(req, res, next){ |
|
|
dope.column(1).write(++total.req); |
|
|
dope.column(1).write(++total.req); |
|
@ -97,20 +81,14 @@ if (argv.help){ |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
--compress enables compression |
|
|
|
|
|
*/ |
|
|
|
|
|
if (argv.compress) app.use(connect.compress()); |
|
|
|
|
|
|
|
|
/* --compress enables compression */ |
|
|
|
|
|
if (argv.compress) app.use(compress()); |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
static file server including directory browsing support |
|
|
|
|
|
*/ |
|
|
|
|
|
app.use(connect.static(path.resolve(argv.directory))) |
|
|
|
|
|
.use(connect.directory(path.resolve(argv.directory), { icons: true })); |
|
|
|
|
|
|
|
|
/* static file server including directory browsing support */ |
|
|
|
|
|
app.use(serveStatic(path.resolve(argv.directory))) |
|
|
|
|
|
.use(directory(path.resolve(argv.directory), { icons: true })); |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
launch server |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* launch server */ |
|
|
var server = http.createServer(app) |
|
|
var server = http.createServer(app) |
|
|
.on("error", function(err){ |
|
|
.on("error", function(err){ |
|
|
if (err.code === "EADDRINUSE"){ |
|
|
if (err.code === "EADDRINUSE"){ |
|
@ -121,18 +99,14 @@ if (argv.help){ |
|
|
}) |
|
|
}) |
|
|
.listen(argv.port); |
|
|
.listen(argv.port); |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
write status to stderr so stdout can be piped to disk ($ ws > log.txt) |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* write status to stderr so stdout can be piped to disk ($ ws > log.txt) */ |
|
|
if (path.resolve(argv.directory) === process.cwd()){ |
|
|
if (path.resolve(argv.directory) === process.cwd()){ |
|
|
dope.error("serving at %underline{%s}", "http://localhost:" + argv.port); |
|
|
dope.error("serving at %underline{%s}", "http://localhost:" + argv.port); |
|
|
} else { |
|
|
} else { |
|
|
dope.error("serving %underline{%s} at %underline{%s}", argv.directory, "http://localhost:" + argv.port); |
|
|
dope.error("serving %underline{%s} at %underline{%s}", argv.directory, "http://localhost:" + argv.port); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
in stats mode, monitor connections and bytes transferred |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* in stats mode, monitor connections and bytes transferred */ |
|
|
if (!argv["log-format"]){ |
|
|
if (!argv["log-format"]){ |
|
|
dope.hideCursor(); |
|
|
dope.hideCursor(); |
|
|
dope.log("%underline{Requests} %underline{Data} %underline{Connections}"); |
|
|
dope.log("%underline{Requests} %underline{Data} %underline{Connections}"); |