diff --git a/lib/install.js b/lib/install.js index bc00769..b986b8a 100644 --- a/lib/install.js +++ b/lib/install.js @@ -6,6 +6,9 @@ var _ = require('lodash'); var assert = require('assert-plus'); var vasync = require('vasync'); var verror = require('verror'); +var compose = require('restify').helpers.compose; +var bunyan = require('bunyan'); +var LOG; /** * Install the enroute routes into the restify server. @@ -23,6 +26,12 @@ function install(opts, cb) { assert.object(opts.server, 'opts.server'); assert.string(opts.basePath, 'opts.basePath'); + if (typeof opts.log !== 'undefined') { + LOG = opts.log.child({ component: 'enroute' }); + } else { + LOG = bunyan.createLogger({name: 'enroute'}); + } + vasync.pipeline({arg: {}, funcs: [ // Read the routes from disk and parse them as functions function getRoutes(ctx, cb1) { @@ -32,6 +41,15 @@ function install(opts, cb) { return cb1(); }); + if (opts.enroute.hotReload) { + if (typeof opts.basePath !== 'undefined') { + LOG.info({basedir: opts.basePath}, + 'Hot reloading of routes is enabled for base dir'); + } else { + LOG.info('Hot reloading of routes is enabled.'); + } + } + // go through each of the route names _.forEach(opts.enroute.routes, function (methods, routeName) { // go through each of the HTTP methods @@ -45,7 +63,12 @@ function install(opts, cb) { route = { name: routeName, method: method, - func: require(sourceFile) + func: opts.enroute.hotReload + ? function (req, resp, callback) { + reloadProxy(sourceFile, req, + resp, callback, opts); + } + : require(sourceFile) }; } catch (e) { return cb1(new verror.VError({ @@ -89,4 +112,31 @@ function install(opts, cb) { }); } +function reloadProxy(sourceFile, req, resp, callback, opts) { + if (typeof opts.basePath !== 'undefined') { + //Delete code loaded from a specific base dir + Object.keys(require.cache).forEach(function (cacheKey) { + if (cacheKey.indexOf(opts.basePath) !== -1) { + delete require.cache[cacheKey]; + } + }); + } else { + //Delete all cached entries + Object.keys(require.cache).forEach(function (cacheKey) { + delete require.cache[cacheKey]; + }); + } + + try { + var handlers = require(sourceFile); + var handlerChain = compose(handlers); + + handlerChain(req, resp, callback); + } catch (e) { + LOG.error('Uncaught error in route:'); + LOG.error(e); + callback(e); + } +} + module.exports = install; diff --git a/lib/schemas.js b/lib/schemas.js index 9b6a801..9021487 100644 --- a/lib/schemas.js +++ b/lib/schemas.js @@ -99,6 +99,9 @@ module.exports = { }, schemaVersion: { type: 'number' + }, + hotReload: { + type: 'boolean' } }, additionalProperties: false, diff --git a/package.json b/package.json index dc25362..3a36987 100644 --- a/package.json +++ b/package.json @@ -37,14 +37,15 @@ "jscs": "^3.0.7", "mocha": "^3.1.2", "nsp": "^2.6.2", - "restify": "^7.0.0", "restify-clients": "^1.4.0", "uuid": "^2.0.3" }, "dependencies": { "ajv": "^4.8.0", "assert-plus": "^1.0.0", + "bunyan": "^1.8.12", "lodash": "^4.16.4", + "restify": "^7.2.0", "vasync": "^1.6.4", "verror": "^1.6.0" }