mirror of
https://github.com/CryptKeeperZK/ejs.git
synced 2026-01-10 07:58:26 -05:00
Added CouchDB storage for sessions.
This commit is contained in:
59
lib/app.js
59
lib/app.js
@@ -1,6 +1,7 @@
|
||||
var http = require('http');
|
||||
var sys = require('sys');
|
||||
var fs = require('fs');
|
||||
|
||||
var fleegix = require('geddy/lib/fleegix');
|
||||
var errors = require('geddy/lib/errors');
|
||||
var session = require('geddy/lib/session');
|
||||
@@ -12,54 +13,52 @@ var Controller = require('./controller').Controller;
|
||||
var App = function (initData) {
|
||||
var _this = this;
|
||||
|
||||
this.initData = initData;
|
||||
this.router = initData.router;
|
||||
this.controllers = initData.controllers;
|
||||
this.templates = initData.templates;
|
||||
|
||||
this.run = function (req, resp) {
|
||||
var url = req.url;
|
||||
var base = fleegix.url.getBase(url);
|
||||
var route = this.router.parse(base, req.method);
|
||||
|
||||
var route = router.parse(base, req.method);
|
||||
|
||||
try {
|
||||
// If the route is a match, run the matching controller/action
|
||||
if (route) {
|
||||
var cook = new cookies.CookieCollection(req);
|
||||
|
||||
|
||||
var sess = new session.Session({
|
||||
app: this,
|
||||
request: req,
|
||||
cookies: cook
|
||||
});
|
||||
|
||||
var qs = fleegix.url.getQS(url);
|
||||
var qsParams = fleegix.url.qsToObject(qs);
|
||||
var params = fleegix.mixin(route.params, qsParams);
|
||||
sess.init(function () {
|
||||
|
||||
// Instantiate the matching controller from the registry
|
||||
var constructor = this.controllers[route.controller];
|
||||
// Give it all the base Controller fu
|
||||
constructor.prototype = new Controller({
|
||||
app: this,
|
||||
request: req,
|
||||
response: resp,
|
||||
name: route.controller,
|
||||
params: params,
|
||||
cookies: cook,
|
||||
session: sess
|
||||
var qs = fleegix.url.getQS(url);
|
||||
var qsParams = fleegix.url.qsToObject(qs);
|
||||
var params = fleegix.mixin(route.params, qsParams);
|
||||
|
||||
// Instantiate the matching controller from the registry
|
||||
var constructor = controllerRegistry[route.controller];
|
||||
// Give it all the base Controller fu
|
||||
constructor.prototype = new Controller({
|
||||
request: req,
|
||||
response: resp,
|
||||
name: route.controller,
|
||||
params: params,
|
||||
cookies: cook,
|
||||
session: sess
|
||||
});
|
||||
var controller = new constructor();
|
||||
|
||||
// Mix in any user-defined Application methods
|
||||
var mixin = new controllerRegistry.Application();
|
||||
|
||||
controller[route.action].call(controller, params);
|
||||
});
|
||||
var controller = new constructor();
|
||||
|
||||
// Mix in any user-defined Application methods
|
||||
var mixin = new this.controllers.Application();
|
||||
|
||||
controller[route.action].call(controller, params);
|
||||
}
|
||||
else {
|
||||
// In dev mode, also serve static files
|
||||
if (initData.environment = 'development') {
|
||||
var path = initData.staticFilePath + req.url;
|
||||
if (config.environment = 'development') {
|
||||
var path = config.staticFilePath + req.url;
|
||||
fs.stat(path, function (err, stats) {
|
||||
// File not found, hand back the 404
|
||||
if (err) {
|
||||
@@ -79,7 +78,7 @@ var App = function (initData) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Catch all errors, respond with error page & HTTP error code
|
||||
// Catch all errors, respond with error page & HTTP error code
|
||||
catch (e) {
|
||||
var r = new response.Response(resp);
|
||||
r.send(e.message, e.statusCode, {'Content-Type': 'text/html'});
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
|
||||
var Config = function (dirname) {
|
||||
|
||||
this.environment = 'development';
|
||||
this.port = 8000;
|
||||
this.dirname = dirname;
|
||||
this.staticFilePath = this.dirname + '/public';
|
||||
this.sessionStore = 'memory';
|
||||
this.staticFilePath = dirname + '/public';
|
||||
this.sessionStore = 'couchdb';
|
||||
this.sessionIdKey = 'sid';
|
||||
this.sessionExpiry = 14 * 24 * 60 * 60;
|
||||
this.dbHostname = 'localhost';
|
||||
this.dbPort = 5984;
|
||||
this.dbName = 'geddy';
|
||||
|
||||
// Override with app-level opts
|
||||
var opts = require(dirname + '/config/config');
|
||||
for (var p in opts) {
|
||||
this[p] = opts[p];
|
||||
}
|
||||
};
|
||||
|
||||
exports.Config = Config;
|
||||
|
||||
@@ -7,8 +7,6 @@ var fleegix = require('./fleegix');
|
||||
|
||||
var Controller = function (obj) {
|
||||
//var Controller = function (app, name, params, req, resp) {
|
||||
// The top-level app
|
||||
this.app = null;
|
||||
// The http.ServerRequest passed to the 'request' event
|
||||
// callback function
|
||||
this.request = null;
|
||||
@@ -82,7 +80,10 @@ Controller.prototype = new function () {
|
||||
var r = new response.Response(this.response);
|
||||
var headers = {'Content-Type': this.contentType};
|
||||
headers['Set-Cookie'] = this.cookies.serialize();
|
||||
r.send(this.content, 200, headers);
|
||||
var content = this.content;
|
||||
this.session.close(function () {
|
||||
r.send(content, 200, headers);
|
||||
});
|
||||
};
|
||||
|
||||
this.negotiateContent = function (frmt) {
|
||||
@@ -192,13 +193,13 @@ Controller.prototype = new function () {
|
||||
|
||||
if (!url) {
|
||||
key = parentNode.dirname + '/' + partial + '.html.ejs';
|
||||
if (this.app.templates[key]) {
|
||||
if (templateRegistry[key]) {
|
||||
url = key;
|
||||
}
|
||||
}
|
||||
if (!url) {
|
||||
key = 'app/views/' + partial + '.html.ejs';
|
||||
if (this.app.config.templates[key]) {
|
||||
if (templateRegistry[key]) {
|
||||
url = key;
|
||||
}
|
||||
}
|
||||
|
||||
40
lib/init.js
40
lib/init.js
@@ -1,24 +1,22 @@
|
||||
var fs = require('fs');
|
||||
var sys = require('sys');
|
||||
var child_process = require('child_process');
|
||||
|
||||
var fleegix = require('geddy/lib/fleegix');
|
||||
var async = require('geddy/lib/async');
|
||||
var session = require('geddy/lib/session');
|
||||
|
||||
var Init = function (config, callback) {
|
||||
|
||||
// Copy all the values from the config
|
||||
for (var p in config) {
|
||||
this[p] = config[p];
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
this.callback = callback;
|
||||
this.router = require(this.dirname + '/config/router').router;
|
||||
this.controllers = {};
|
||||
this.templates = {};
|
||||
var _callback = callback;
|
||||
|
||||
this.createControllers = function (err, dirList) {
|
||||
GLOBAL.controllerRegistry = {};
|
||||
GLOBAL.templateRegistry = {};
|
||||
GLOBAL.config = config;
|
||||
GLOBAL.router = require(config.dirname + '/config/router').router;
|
||||
|
||||
this.registerControllers = function (err, dirList) {
|
||||
var fileName, controllerName;
|
||||
var controllers = {};
|
||||
var jsPat = /\.js$/;
|
||||
@@ -36,14 +34,14 @@ var Init = function (config, callback) {
|
||||
controllerName = fleegix.string.capitalize(controllerName);
|
||||
// Registers as a controller, e.g., controllers.NeilPearts =
|
||||
// require('/path/to/geddy_app/app/controllers/neil_pearts').NeilPearts
|
||||
controllers[controllerName] = require(_this.dirname +
|
||||
controllers[controllerName] = require(config.dirname +
|
||||
'/app/controllers/' + fileName)[controllerName];
|
||||
}
|
||||
}
|
||||
_this.controllers = controllers;
|
||||
GLOBAL.controllerRegistry = controllers;
|
||||
};
|
||||
|
||||
this.createTemplates = function (err, stdin, stderr) {
|
||||
this.registerTemplates = function (err, stdin, stderr) {
|
||||
if (err) {
|
||||
sys.puts('Error: ' + JSON.stringify(err));
|
||||
}
|
||||
@@ -58,32 +56,32 @@ var Init = function (config, callback) {
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
file = files[i];
|
||||
if (pat.test(file)) {
|
||||
file = file.replace(_this.dirname + '/', '');
|
||||
file = file.replace(config.dirname + '/', '');
|
||||
templates[file] = true;
|
||||
}
|
||||
}
|
||||
_this.templates = templates;
|
||||
GLOBAL.templateRegistry = templates;
|
||||
}
|
||||
};
|
||||
|
||||
session.createStore(this.sessionStore);
|
||||
session.createStore(config.sessionStore);
|
||||
|
||||
var cmdList = [
|
||||
{
|
||||
func: fs.readdir,
|
||||
args: [this.dirname + '/app/controllers'],
|
||||
callback: this.createControllers
|
||||
args: [config.dirname + '/app/controllers'],
|
||||
callback: this.registerControllers
|
||||
},
|
||||
{
|
||||
func: child_process.exec,
|
||||
args: ['find ' + this.dirname + '/app/views'],
|
||||
callback: this.createTemplates
|
||||
args: ['find ' + config.dirname + '/app/views'],
|
||||
callback: this.registerTemplates
|
||||
}
|
||||
];
|
||||
|
||||
var chain = new async.AsyncChain(cmdList);
|
||||
chain.last = function () {
|
||||
_this.callback(_this);
|
||||
_callback();
|
||||
};
|
||||
chain.run();
|
||||
}
|
||||
|
||||
@@ -21,54 +21,54 @@ var session = new function () {
|
||||
|
||||
this.createStore = function (type) {
|
||||
var key = fleegix.string.capitalize(type);
|
||||
session.store = new session[key + 'SessionStore']();
|
||||
var constructor = require('geddy/lib/session_stores/' + type)[key];
|
||||
session.store = new constructor();
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
session.MemorySessionStore = function () {
|
||||
var _sessions = {};
|
||||
this.get = function (sid, key, val) {
|
||||
if (!_sessions[sid]) {
|
||||
_sessions[sid] = {};
|
||||
}
|
||||
return _sessions[sid][key];
|
||||
};
|
||||
|
||||
this.set = function (sid, key, val) {
|
||||
if (!_sessions[sid]) {
|
||||
_sessions[sid] = {};
|
||||
}
|
||||
_sessions[sid][key] = val;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
session.Session = function (obj) {
|
||||
this.store = null;
|
||||
this.sid = '';
|
||||
// Copy all props passed in from the app
|
||||
for (var p in obj) {
|
||||
this[p] = obj[p];
|
||||
}
|
||||
var keyName = this.app.initData.sessionIdKey;
|
||||
var keyName = config.sessionIdKey;
|
||||
var sid = this.cookies.get(keyName);
|
||||
if (!sid) {
|
||||
sid = session.generateSessionId()
|
||||
var dt = new Date();
|
||||
dt.setTime(dt.getTime() + (this.app.initData.sessionExpiry * 1000));
|
||||
dt.setTime(dt.getTime() + (config.sessionExpiry * 1000));
|
||||
this.cookies.set(keyName, sid, {expires: dt.toGMTString()});
|
||||
}
|
||||
this.sid = sid;
|
||||
};
|
||||
|
||||
session.Session.prototype = new function () {
|
||||
this.init = function(appCallback) {
|
||||
var _this = this;
|
||||
var localCallback = function (result) {
|
||||
_this.store = result;
|
||||
appCallback();
|
||||
};
|
||||
session.store.read(this.sid, localCallback);
|
||||
};
|
||||
|
||||
this.get = function (key) {
|
||||
return session.store.get(this.id, key);
|
||||
sys.puts(JSON.stringify(this.store));
|
||||
return this.store[key];
|
||||
};
|
||||
|
||||
this.set = function (key, val) {
|
||||
return session.store.set(this.id, key, val);
|
||||
this.store[key] = val;
|
||||
sys.puts(JSON.stringify(this.store));
|
||||
};
|
||||
|
||||
this.close = function (appCallback) {
|
||||
session.store.write(this.sid, this.store, appCallback);
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
for (var p in session) { this[p] = session[p]; }
|
||||
|
||||
98
lib/session_stores/couchdb.js
Normal file
98
lib/session_stores/couchdb.js
Normal file
@@ -0,0 +1,98 @@
|
||||
var sys = require("sys");
|
||||
var http = require("http");
|
||||
|
||||
var Couchdb = function () {
|
||||
var _this = this;
|
||||
var _sessions = {};
|
||||
var _readCallback;
|
||||
var _writeCallback;
|
||||
|
||||
this.read = function (sid, callback) {
|
||||
_readCallback = callback;
|
||||
this.request({url: '/' + config.dbName +
|
||||
'/' + sid, method: 'GET'}, this.ensureRead);
|
||||
};
|
||||
|
||||
this.ensureRead = function (response) {
|
||||
if (response.statusCode == 404) {
|
||||
_this.create(response);
|
||||
}
|
||||
else {
|
||||
var url = response.url;
|
||||
var sid = url.substr(url.lastIndexOf('/') + 1);
|
||||
var data = JSON.parse(response.body);
|
||||
_sessions[sid] = data;
|
||||
_readCallback(_sessions[sid]);
|
||||
}
|
||||
};
|
||||
|
||||
this.create = function (response) {
|
||||
var url = response.url;
|
||||
var sid = url.substr(url.lastIndexOf('/') + 1);
|
||||
this.request({url: '/' + config.dbName +
|
||||
'/' + sid, method: 'PUT', data: {}}, this.ensureRead);
|
||||
};
|
||||
|
||||
this.ensureCreate = function (response) {
|
||||
if (response.statusCode == 201) {
|
||||
var url = response.url;
|
||||
var sid = url.substr(url.lastIndexOf('/') + 1);
|
||||
var data = JSON.parse(response.body);
|
||||
_sessions[sid] = data;
|
||||
_readCallback(_sessions[sid]);
|
||||
}
|
||||
else {
|
||||
throw new Error('could not create CouchDB session.');
|
||||
}
|
||||
};
|
||||
|
||||
this.write = function (sid, store, callback) {
|
||||
this.request({url: '/' + config.dbName +
|
||||
'/' + sid, method: 'PUT', data: store}, this.ensureUpdate);
|
||||
_writeCallback = callback;
|
||||
};
|
||||
|
||||
this.ensureUpdate = function (response) {
|
||||
_writeCallback();
|
||||
};
|
||||
|
||||
this.request = function (params, callback) {
|
||||
var req = {};
|
||||
req.url = params.url;
|
||||
req.method = params.method || 'GET';
|
||||
req.data = JSON.stringify(params.data) || null;
|
||||
|
||||
var headers = {host: config.dbHostname};
|
||||
if (req.data) {
|
||||
headers['content-length'] = req.data.length;
|
||||
}
|
||||
|
||||
var client = http.createClient(config.dbPort, config.dbHostname);
|
||||
var request = client.request(req.method, req.url, headers);
|
||||
request.addListener('response', function (response) {
|
||||
//sys.puts("STATUS: " + response.statusCode);
|
||||
//sys.puts("HEADERS: " + JSON.stringify(response.headers));
|
||||
response.setBodyEncoding("utf8");
|
||||
response.addListener("data", function (chunk) {
|
||||
//sys.puts("BODY: " + chunk);
|
||||
callback({
|
||||
url: req.url,
|
||||
statusCode: response.statusCode,
|
||||
body: chunk
|
||||
});
|
||||
});
|
||||
});
|
||||
if (req.data) {
|
||||
request.write(req.data);
|
||||
}
|
||||
request.close();
|
||||
};
|
||||
|
||||
// TODO: Create the correctly named DB on app startup if it's not there
|
||||
//this.request({url: '/' + config.dbName, method: 'PUT'}, this.ensureRead);
|
||||
|
||||
};
|
||||
|
||||
|
||||
exports.Couchdb = Couchdb;
|
||||
|
||||
18
lib/session_stores/memory.js
Normal file
18
lib/session_stores/memory.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
var Memory = function () {
|
||||
var _sessions = {};
|
||||
|
||||
this.read = function (sid, callback) {
|
||||
if (!_sessions[sid]) {
|
||||
_sessions[sid] = {};
|
||||
}
|
||||
callback(_sessions[sid]);
|
||||
};
|
||||
|
||||
this.write = function (sid, store, callback) {
|
||||
callback();
|
||||
};
|
||||
};
|
||||
|
||||
exports.Memory = Memory;
|
||||
|
||||
@@ -2,21 +2,23 @@ var appDirname = process.argv[2];
|
||||
|
||||
var sys = require('sys');
|
||||
var http = require('http');
|
||||
|
||||
var fleegix = require('geddy/lib/fleegix');
|
||||
|
||||
var Config = require('geddy/lib/config').Config;
|
||||
var Init = require('geddy/lib/init').Init;
|
||||
var App = require('geddy/lib/app').App;
|
||||
|
||||
config = new Config(appDirname);
|
||||
config = fleegix.mixin(config, require(config.dirname + '/config/config'));
|
||||
|
||||
var runServ = function (initData) {
|
||||
var runServ = function () {
|
||||
http.createServer(function (req, resp) {
|
||||
new App(initData).run(req, resp);
|
||||
new App().run(req, resp);
|
||||
}).listen(config.port);
|
||||
|
||||
sys.puts('Server running at http://127.0.0.1:' + config.port + '/');
|
||||
};
|
||||
|
||||
var config = new Config(appDirname);
|
||||
// Initialize the app, passing in the config, and runServ at its callback
|
||||
new Init(config, runServ);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user