exprimus
Version:
Binds Express and any real time engine through Primus
209 lines (193 loc) • 5.88 kB
JavaScript
var Primus = require('primus')
, SparkRequest = require('./request')
, SparkResponse = require('./response')
, Route = require('./route')
, extend = require('node.extend')
, primusSession = require('./session')
, cookieParser = require('cookie-parser')
, expressSession = require('express-session')
;
var verbs = ['all','get','post','put','delete'];
function PrimusRouter(app){
var methods = {
app:app
, _meta:{}
};
var properties = {
'views':''
, 'view engine':'jade'
, 'transformer':'websocket'
}
var routes = [];
var verb,i=0;
while(verb = verbs[i++]){
methods[verb] = onVerb(verb,routes).bind(methods);
}
methods.use = onVerb('use',routes).bind(methods);
methods.set = setProperty.bind(methods,properties);
methods.listen = listen.bind(methods,methods,routes,properties);
methods.render = render.bind(methods,properties);
methods.send = send.bind(methods);
methods.routes = routes;
methods.connect = connect.bind(methods,methods,routes,properties);
methods.cookie = cookie.bind(methods,methods,properties);
methods.session = session.bind(methods,methods,properties);
methods.session.MemoryStore = expressSession.MemoryStore;
return methods;
};
function cookie(methods,properties,secret){
secret = secret || properties.secret;
var app = methods.app;
if(!secret){throw new Error('no secret set for cookies');}
if(!app){throw new Error('you must create an app before setting cookies');}
var cookiesMiddleware = cookieParser(secret);
app.use(cookiesMiddleware);
methods._meta.cookie = cookiesMiddleware;
}
function session(methods,properties,secret,store){
secret = secret || properties.secret;
store = store || properties.store;
var app = methods.app;
if(!store){throw new Error('no store set for session');}
if(!secret){throw new Error('no secret set for session');}
if(!app){throw new Error('you must create an app before setting session');}
if(!methods._meta.cookie){
cookie(methods,properties,secret);
}
var sessionMiddleWare = expressSession({
saveUninitialized: true
, secret: secret
, resave: true
, store: store
});
app.use(sessionMiddleWare);
methods._meta.session = store;
}
function send(){
return function sparkSend(spark,data){
if(typeof data == 'string'){data = {response:data};}
else if(data instanceof Error){data = {
error:{
message: data.message
, name: data.name
}
};}
spark.write(data);
}
}
function render(properties){
var path = properties['views']
var engineName = properties['view engine'];
if(!path){throw new Error('no views path set for render');}
if(!engineName){throw new Error('no engine set for render');}
engine = require(engineName);
renderFunction = engine.__express;
return function sparkRender(spark,view,data){
view = view || data.view || 'index';
path+='/'+view+'.'+engineName;
var locals = extend(true,{skipLayout:true},this.locals,data)
var rendered = renderFunction(path,locals);
locals.render = rendered;
spark.write(locals);
}
}
function listen(methods,routes,properties,port,cb,fn){
if((typeof port == 'number' || typeof port == 'string')){
if(!this.app){
throw new Error("you must create an express app and pass it to primusRouter before calling listen");
}
var server = this.app.listen(this.app.get('port'),function(){
cb();
});
this.connect(server,fn);
return server;
}
return this.connect(port,cb);
}
function connect(methods,routes,properties,server,fn){
var primus = new Primus(server,properties);
var onPrimusConnection = onPrimusConnectionMaker(properties,routes);
methods.library = primus.library.bind(primus);
methods.save = primus.save.bind(primus);
methods.write = primus.write.bind(primus);
methods.forEach = primus.forEach.bind(primus);
methods.primus = primus;
if(methods._meta.cookie){
primus.before('cookies', methods._meta.cookie);
}
if(methods._meta.session){
primus.before('session', primusSession, { store: methods._meta.session });
}
primus.on('connection',function connection(spark){
if(fn){fn(spark);}
spark.on('data',onPrimusConnection(spark));
});
return this;
}
function setProperty(properties,prop,val){
if(arguments.length<3){
return properties[prop];
}
properties[prop] = val;
if(this.app){this.app.set(prop,val);}
return this;
}
function onVerb(method,routes){
return function(/**path,functions**/){
if(arguments.length==1 && method=='get'){return this.set(arguments[0]);}
var args = new Array(arguments.length), i = 0, path = '',arg;
while(arg = arguments[i]){args[i++] = arg;};
if(this.app){
this.app[method].apply(this.app,args);
}
if(typeof args[0] !== 'function'){path = args.shift();}
var route = Route(path,method,args);
routes.push(route)
return this;
}
}
function onPrimusConnectionMaker(properties,routes){
var l = routes.length;
var SparkResponseFactory = SparkResponse(properties);
return function onPrimusConnection(spark){
return function onSparkData(data){
if(typeof data == 'string'){data = {url:data};}
if(!data.url){return;}
var i = 0
, fn
, route
, errors = []
, req = SparkRequest(spark,data)
, res = SparkResponseFactory(spark)
, params
;
(function next(err){
if(err){errors = errors.concat(err);}
if(i>=l){
if(errors.length){
res.send(errors[0]);
return;
}
var err = new Error('could not '+req.method+' '+req.url);
err.status = 404;
res.send(err);
return;
}
route = routes[i++];
if(errors.length && route.handleErrors && (params = route.match(req.url,req.method))){
req.params = params;
route.process(errors,req,res,next);
return;
}
//console.log(route.path,route.method,req.url)
if(params = route.match(req.url,req.method)){
req.params = params;
route.process(req,res,next);
return;
}
next();
})();
}
}
}
module.exports = PrimusRouter;