mors
Version:
Express inspired mqtt development framework based on mosca for node
131 lines (101 loc) • 2.54 kB
JavaScript
;
const debug = require('debug')('mors:router');
const Routes = require('./routes');
const methods = require('../methods');
const utils = require('../utils');
const slice = Array.prototype.slice;
const proto = module.exports = function () {
function router(req, res, next) {
return router.handle(req, res, next);
}
// mixin Router class functions
router.__proto__ = proto;
router.routes = new Routes();
return router;
};
/**
*
* @param req
* @param res
* @param done
* @returns {boolean}
*/
proto.handle = function (req, res, done) {
const self = this;
debug('dispatching %s', req.topic);
let match = {
next: function () {
return self.routes.match(req.topic);
}
};
done = done || function (err) {
if (err) throw err;
};
req.next = next;
next();
function next(err) {
const layerError = err === 'route' ? null : err;
if (!match || !(match = match.next())) return done(layerError);
const layer = match.layer;
if (match.method) {
const method = req.method;
if (!method || method.toLowerCase() !== match.method) return next();
}
req.route = routeFromMatch(match);
req.params = match.params;
req.splats = match.splats;
debug('%s %s : %s', layer.name, match.route, req.topic);
if (layerError) {
layer.handle_error(layerError, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}
};
proto.use = function (fn) {
let offset = 0;
let path = '*';
// default path to '*'
if (typeof fn !== 'function') {
offset = 1;
path = fn;
}
const callbacks = utils.flatten(slice.call(arguments, offset));
if (callbacks.length === 0) {
throw new TypeError('Router.use() requires callback function');
}
const routes = this.routes;
callbacks.forEach(function (fn) {
if (typeof fn !== 'function') {
const type = toString.call(fn);
const msg = 'Router.use() requires callback function but got a ' + type;
throw new TypeError(msg);
}
// add the middleware
debug('use %s %s', path, fn.name || '<anonymous>');
const route = routes.addRoute(path);
route.all(fn);
});
return this;
};
/**
*
* @param {String} path
*/
proto.route = function (path) {
return this.routes.addRoute(path);
};
methods.concat('all').forEach(function (method) {
proto[method] = function (path) {
const route = this.routes.addRoute(path);
route[method].apply(route, slice.call(arguments, 1));
return this;
}
});
function routeFromMatch(match) {
return {
params: match.params,
splats: match.splats,
path: match.route
}
}