npm-debug.log | npm-debug.log | ||||
imgs | imgs | ||||
!imgs/.placeholder | !imgs/.placeholder | ||||
.currentRun |
"dir": { | "dir": { | ||||
"imgs": "imgs" | "imgs": "imgs" | ||||
}, | }, | ||||
"debug": false | |||||
"debug": false, | |||||
"maxRuns": 9999 | |||||
} | } |
var formidable = require("formidable"); | var formidable = require("formidable"); | ||||
var crypto = require("crypto"); | var crypto = require("crypto"); | ||||
var zlib = require("zlib"); | |||||
var preprocess = require("./preprocess.js"); | var preprocess = require("./preprocess.js"); | ||||
var sessions = {}; | var sessions = {}; | ||||
env.url = ctx.req.url; | env.url = ctx.req.url; | ||||
str = preprocess(str, { | str = preprocess(str, { | ||||
session: ctx.session, | |||||
session: function(key) { | |||||
ctx.cachable = false; | |||||
return ctx.session[key]; | |||||
}, | |||||
arg: function(key) { | arg: function(key) { | ||||
return ctx.htmlEntities(args[key]); | return ctx.htmlEntities(args[key]); | ||||
}, | }, | ||||
return str; | return str; | ||||
} | } | ||||
var cache = {}; | |||||
module.exports = function(options) { | module.exports = function(options) { | ||||
this.req = options.req; | this.req = options.req; | ||||
this.res = options.res; | this.res = options.res; | ||||
this.db = options.db; | this.db = options.db; | ||||
this.conf = options.conf; | this.conf = options.conf; | ||||
this.query = this.req.url.split("?")[1] || ""; | this.query = this.req.url.split("?")[1] || ""; | ||||
this.shouldGzip = /gzip/.test(this.req.headers["accept-encoding"]); | |||||
this.cachable = true; | |||||
this.statusCode = 200; | |||||
this.headers = {}; | |||||
if (this.conf.debug) | if (this.conf.debug) | ||||
this.startTime = new Date(); | this.startTime = new Date(); | ||||
} | } | ||||
module.exports.prototype = { | module.exports.prototype = { | ||||
end: function(str) { | |||||
_end: function(str) { | |||||
if (this.conf.debug) { | if (this.conf.debug) { | ||||
var ms = (new Date().getTime() - this.startTime.getTime()); | var ms = (new Date().getTime() - this.startTime.getTime()); | ||||
console.log( | console.log( | ||||
conole.log(this.req.url); | conole.log(this.req.url); | ||||
} | } | ||||
if (this.statusCode) | |||||
this.res.writeHead(this.statusCode); | |||||
this.res.writeHead(this.statusCode, this.headers); | |||||
this.res.end(str); | this.res.end(str); | ||||
}, | }, | ||||
end: function(str, alreadyGzipped) { | |||||
if (!this.shouldGzip) | |||||
return this._end(str); | |||||
this.setHeader("Content-Encoding", "gzip"); | |||||
if (alreadyGzipped) | |||||
return this._end(str); | |||||
zlib.gzip(str, function(err, res) { | |||||
if (err) | |||||
throw err; | |||||
this._end(res); | |||||
}.bind(this)); | |||||
}, | |||||
succeed: function(obj) { | succeed: function(obj) { | ||||
obj = obj || {}; | obj = obj || {}; | ||||
obj.success = true; | obj.success = true; | ||||
this.res.setHeader("Content-Type", "application/json"); | |||||
this.setHeader("Content-Type", "application/json"); | |||||
this.end(JSON.stringify(obj)); | this.end(JSON.stringify(obj)); | ||||
}, | }, | ||||
console.log("Sending error to client:"); | console.log("Sending error to client:"); | ||||
console.trace(err); | console.trace(err); | ||||
this.res.setHeader("Content-Type", "application/json"); | |||||
this.setHeader("Content-Type", "application/json"); | |||||
obj = {}; | obj = {}; | ||||
obj.success = false; | obj.success = false; | ||||
if (!str) | if (!str) | ||||
throw new Error("No such view: "+name); | throw new Error("No such view: "+name); | ||||
if (name === "404") | |||||
this.setStatus(404); | |||||
return templatify(str, args, this, {view: name}); | return templatify(str, args, this, {view: name}); | ||||
}, | }, | ||||
this.statusCode = code; | this.statusCode = code; | ||||
}, | }, | ||||
setHeader: function(key, val) { | |||||
this.headers[key] = val; | |||||
}, | |||||
login: function(username, id) { | login: function(username, id) { | ||||
this.session.loggedIn = true; | this.session.loggedIn = true; | ||||
this.session.username = username; | this.session.username = username; |
var fs = require("fs"); | var fs = require("fs"); | ||||
var zlib = require("zlib"); | |||||
var minify = require("./minify.js"); | var minify = require("./minify.js"); | ||||
var includeHtml = require("./includeHtml.js"); | var includeHtml = require("./includeHtml.js"); | ||||
//If it doesn't end with .node.js, it's a regular text file and will | //If it doesn't end with .node.js, it's a regular text file and will | ||||
//just be served as is | //just be served as is | ||||
} else { | } else { | ||||
res.endpoints[i] = fs.readFileSync(conf.webroot+"/"+ep, "utf8"); | |||||
var str = fs.readFileSync(conf.webroot+"/"+ep, "utf8"); | |||||
//If it's an HTML file, we minify it | //If it's an HTML file, we minify it | ||||
if (!conf.minify) { | if (!conf.minify) { | ||||
//Don't minify unless the conf tells us to | //Don't minify unless the conf tells us to | ||||
} else if (/\.html$/.test(ep)) { | } else if (/\.html$/.test(ep)) { | ||||
res.endpoints[i] = minify.html(res.endpoints[i]); | |||||
str = minify.html(str); | |||||
} else if (/\.js$/.test(ep)) { | } else if (/\.js$/.test(ep)) { | ||||
res.endpoints[i] = minify.js(res.endpoints[i]); | |||||
str = minify.js(str); | |||||
} else if (/\.css$/.test(ep)) { | } else if (/\.css$/.test(ep)) { | ||||
res.endpoints[i] = minify.css(res.endpoints[i]); | |||||
str = minify.css(str); | |||||
} | } | ||||
res.endpoints[i] = str; | |||||
} | } | ||||
//Errors will usually be because an endpoint doesn't exist | //Errors will usually be because an endpoint doesn't exist |
var https = require("https"); | var https = require("https"); | ||||
var fs = require("fs"); | var fs = require("fs"); | ||||
var domain = require("domain"); | var domain = require("domain"); | ||||
var zlib = require("zlib"); | |||||
var loader = require("./lib/loader.js"); | var loader = require("./lib/loader.js"); | ||||
var pg = require("pg"); | var pg = require("pg"); | ||||
var Context = require("./lib/context.js"); | var Context = require("./lib/context.js"); | ||||
"/api/account_change_password": "api/account_change_password.node.js" | "/api/account_change_password": "api/account_change_password.node.js" | ||||
} | } | ||||
//We cache static resources for a long time. However, we want to invalidate | |||||
//the browser's cache whenever a file updates. Therefore, we append | |||||
//a number to all static files, and the number increases every time we start | |||||
//the server. currentRun is that number. | |||||
var currentRun; | |||||
try { | |||||
currentRun = parseInt(fs.readFileSync(".currentRun", "utf8")); | |||||
} catch (err) { | |||||
if (err.code === "ENOENT") | |||||
currentRun = 0; | |||||
else | |||||
throw err; | |||||
} | |||||
currentRun = (currentRun >= conf.maxRuns ? 0 : currentRun); | |||||
currentRun = (currentRun || 0) + 1; | |||||
conf.web.currentRun = currentRun.toString(); | |||||
fs.writeFileSync(".currentRun", currentRun, "utf8"); | |||||
var loaded = loader.load(endpoints, conf); | var loaded = loader.load(endpoints, conf); | ||||
var db = new pg.Client(conf.db); | var db = new pg.Client(conf.db); | ||||
var gzipCache = {}; | |||||
//Function to run on each request | //Function to run on each request | ||||
function onRequest(req, res) { | function onRequest(req, res) { | ||||
var ctx = new Context({ | var ctx = new Context({ | ||||
if (typeof ep == "function") { | if (typeof ep == "function") { | ||||
ep(ctx); | ep(ctx); | ||||
} else { | } else { | ||||
ctx.end(ep); | |||||
//Cache content for a year | |||||
ctx.setHeader("Cache-Control", "public, max-age=31536000"); | |||||
//Gzip and such | |||||
if (ctx.shouldGzip && gzipCache[req.url]) { | |||||
ctx.end(gzipCache[req.url], true); | |||||
} else if (ctx.shouldGzip) { | |||||
zlib.gzip(ep, function(err, res) { | |||||
gzipCache[req.url] = res; | |||||
ctx.end(res, true); | |||||
}); | |||||
} else { | |||||
ctx.end(ep); | |||||
} | |||||
} | } | ||||
} | } | ||||
//Initiate a postgresql client | //Initiate a postgresql client | ||||
db.connect(function() { | db.connect(function() { | ||||
//Create HTTP or HTTPS server | //Create HTTP or HTTPS server | ||||
var server; | var server; | ||||
if (conf.use_https) { | if (conf.use_https) { | ||||
console.trace(err); | console.trace(err); | ||||
}); | }); | ||||
} | } | ||||
function command(tokens) { | |||||
switch(tokens[0]) { | |||||
//Reload configuration | |||||
case "reload-conf": | |||||
var c = JSON.parse(fs.readFileSync("conf.json")); | |||||
for (var i in c) | |||||
conf[i] = c[i]; | |||||
break; | |||||
//Reload HTML | |||||
case "reload-html": | |||||
var l = loader.load(endpoints, conf); | |||||
for (var i in l) | |||||
loaded[i] = l[i]; | |||||
break; | |||||
//Reload everything | |||||
case "reload": | |||||
command(["reload-conf"]); | |||||
command(["reload-html"]); | |||||
break; | |||||
default: return false; | |||||
} | |||||
return true; | |||||
} | |||||
process.stdin.on("data", function(line) { | |||||
var tokens = line.toString().split(/\s+/); | |||||
if (command(tokens)) { | |||||
return console.log(tokens[0]+" completed successfully."); | |||||
} else { | |||||
return console.log("Command not found: "+tokens[0]); | |||||
} | |||||
}); |
<meta charset="utf-8"> | <meta charset="utf-8"> | ||||
<meta name="viewport" content="width=device-width"> | <meta name="viewport" content="width=device-width"> | ||||
<link rel="stylesheet" href="/global.css"> | |||||
<link rel="stylesheet" href="/global.css?{{conf#currentRun}}"> | |||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> | <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> | ||||
<link rel="stylesheet" href="/{{env#view}}/style.css"> | |||||
<link rel="stylesheet" href="/{{env#view}}/style.css?{{conf#currentRun}}"> | |||||
<script src="https://code.jquery.com/jquery-2.1.4.js"></script> | <script src="https://code.jquery.com/jquery-2.1.4.js"></script> | ||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> | <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> | ||||
<script src="/global.js"></script> | |||||
<script src="/{{env#view}}/script.js"></script> | |||||
<script src="/global.js?{{conf#currentRun}}"></script> | |||||
<script src="/{{env#view}}/script.js?{{conf#currentRun}}"></script> |