rig
Version:
A barepipe platform for node webapps
111 lines (100 loc) • 4.22 kB
JavaScript
/*jslint forin: true, nomen: true */
var async = require('async'),
Rig = require('../rig.js'),
registry = Rig.registry,
stupidController = function (req, res, done) {
done();
};
module.exports = function (options) {
'use strict';
var dispatchPlan = function (plan, req, res, planDone) {
var controller,
key,
toFlushInOrder,
expandedPlan,
retentionPool = {};
if (typeof plan === 'string') {
expandedPlan = options.details[plan];
if (expandedPlan instanceof Array) {
return dispatchPlan(expandedPlan, req, res, planDone);
}
// if there is no controller, just render the static template with nothing
controller = registry.get('controllers.' + plan);
if (!controller) {
controller = stupidController;
console.warn('[Dispatcher] Cannot find resource controllers.' + plan + ', rendering corresponding view as static.');
}
if (expandedPlan instanceof Object) {
for (key in expandedPlan) {
retentionPool[key] = dispatchPlan.bind(null, expandedPlan[key], req, res);
}
retentionPool[plan] = controller.bind(null, req, res);
return async.parallel(retentionPool, function (err, preRenderedBits) {
var key;
for (key in preRenderedBits[plan]) {
preRenderedBits[key] = preRenderedBits[plan][key];
}
preRenderedBits._csrf = req.session._csrf;
return res.render(plan + '.html', preRenderedBits, planDone);
});
}
return controller(req, res, function renderResult(err, result) {
if (err) {
return planDone(err);
}
result = result || {};
result._csrf = req.session._csrf;
return res.render(plan + '.html', result, planDone);
});
}
if (plan instanceof Array) {
toFlushInOrder = plan.concat();
return async.each(plan, function dispatchAndSchedule(subplan, subplanDone) {
dispatchPlan(subplan, req, res, function scheduleRendered(err, html) {
if (err) {
return subplanDone(err);
}
retentionPool[subplan] = html;
while (retentionPool.hasOwnProperty(toFlushInOrder[0])) {
res.write(retentionPool[toFlushInOrder.shift()] || '');
}
return subplanDone();
});
}, planDone);
}
};
/**
* @name req
* @type {Object}
* @global
* @namespace
* @description the request object passed to every middleware and controller as a first argument
*/
/**
* @name res
* @type {Object}
* @global
* @namespace
* @description the response object passed to every middleware and controller as a second argument
*/
return function dispatcher(req, res, next) {
var h,
reqPath = req.route.path;
// read the plan from the options given the matched route and method
req.plan = options.plans[reqPath] &&
(options.plans[reqPath][req.route.method] || options.plans[reqPath].all);
if (!req.plan) {
return next(new Error('No plan for route ' + reqPath));
}
for (h in options.headers[reqPath]) {
res.setHeader(h, options.headers[reqPath][h]);
}
// initiate the recursive dispatch of the plan
return dispatchPlan(req.plan, req, res, function done(err, result) {
if (!err) {
return res.end(result);
}
next(err);
});
};
};