From de1b325145280891cbb5a9a01d3395b684e92045 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 20 Feb 2013 12:17:48 -0800 Subject: [PATCH 1/2] Composer --- bin/hapi | 31 ++++++++++ examples/composer.json | 27 ++++++++ lib/composer.js | 115 +++++++++++++++++++++++++++++++++++ lib/index.js | 3 +- lib/pack.js | 2 +- lib/server.js | 3 + package.json | 9 ++- test/integration/composer.js | 66 ++++++++++++++++++++ 8 files changed, 252 insertions(+), 4 deletions(-) create mode 100755 bin/hapi create mode 100755 examples/composer.json create mode 100755 lib/composer.js create mode 100755 test/integration/composer.js diff --git a/bin/hapi b/bin/hapi new file mode 100755 index 000000000..c684b728d --- /dev/null +++ b/bin/hapi @@ -0,0 +1,31 @@ +#!/usr/bin/env node + +var Optimist = require('optimist'); +var Hapi = require('../'); + +var argv = Optimist.usage('Usage: $0 -c config.json') + .demand(['c']) + .argv; + +var options = null; +try { + options = require(process.cwd() + '/' + argv.c); +} +catch (err) { + console.log('Failed loading configuration file: ' + argv.c + ' (' + err.message + ')'); + process.exit(1); +} + +var composer = new Hapi.Composer(options); +composer.compose(function (err) { + + Hapi.utils.assert(!err, 'Failed loading plugins: ' + (err && err.message)); + composer.start(function (err) { + + Hapi.utils.assert(!err, 'Failed starting server: ' + (err && err.message)); + }); +}); + + + + diff --git a/examples/composer.json b/examples/composer.json new file mode 100755 index 000000000..42b5fc20e --- /dev/null +++ b/examples/composer.json @@ -0,0 +1,27 @@ +{ + "servers": { + "ren": { + "host": "localhost", + "port": 8001, + "labels": ["api", "nasty"], + "config": { + "monitor": { + "subscribers": { + "console": ["ops", "request", "log"] + } + }, + "cache": "redis" + } + }, + "stimpy": { + "port": 8002, + "labels": ["api", "nice"] + } + }, + "plugins": { + "furball": { + "version": false, + "plugins": "/" + } + } +} diff --git a/lib/composer.js b/lib/composer.js new file mode 100755 index 000000000..10a829ac4 --- /dev/null +++ b/lib/composer.js @@ -0,0 +1,115 @@ +// Load modules + +var Async = require('async'); +var Server = require('./server'); +var Pack = require('./pack'); +var Utils = require('./utils'); + + +// Declare internals + +var internals = {}; + +/* +var options = [{ + servers: { + ren: { + port: 8001, + labels: ['api', 'nasty'], + config: { + monitor: { + subscribers: { + console: ['ops', 'request', 'log'] + } + }, + cache: 'redis' + } + }, + stimpy: { + host: 'localhost', + port: 8002, + labels: ['api', 'nice'] + } + }, + plugins: { + furball: { + version: false, + plugins: '/' + } + } +}]; +*/ + +exports = module.exports = internals.Composer = function (options) { + + this.settings = Utils.clone(options); + if (this.settings instanceof Array === false) { + this.settings = [this.settings]; + } + + this.packs = []; + + return this; +}; + + +internals.Composer.prototype.compose = function (callback) { + + var self = this; + + // Create packs + + var sets = []; + this.settings.forEach(function (set) { + + Utils.assert(set.servers && Object.keys(set.servers).length, 'Pack missing servers definition'); + + var pack = new Pack(); + Object.keys(set.servers).forEach(function (serverName) { + + // Load servers + + var serverOptions = set.servers[serverName]; + pack.server(serverName, new Server(serverOptions.host, serverOptions.port, serverOptions.config), { labels: serverOptions.labels }); + }); + + sets.push({ pack: pack, plugins: set.plugins }); + self.packs.push(pack); + }); + + // Register plugins + + Async.forEachSeries(sets, function (set, next) { + + set.pack.require(set.plugins, next); + }, + function (err) { + + return callback(err); + }); +}; + + +internals.Composer.prototype.start = function (callback) { + + Async.forEachSeries(this.packs, function (pack, next) { + + pack.start(next); + }, + function (err) { + + Utils.assert(!err, 'Failed starting plugins: ' + (err && err.message)); + return callback(); + }); +}; + + +internals.Composer.prototype.stop = function () { + + this.packs.forEach(function (pack) { + + pack.stop(); + }); +}; + + diff --git a/lib/index.js b/lib/index.js index 13899d1ba..875368fdf 100755 --- a/lib/index.js +++ b/lib/index.js @@ -9,7 +9,8 @@ var internals = { response: require('./response'), utils: require('./utils'), types: require('joi').Types, - pack: require('./pack') + pack: require('./pack'), + composer: require('./composer') } }; diff --git a/lib/pack.js b/lib/pack.js index 73254a017..f9b6879bc 100755 --- a/lib/pack.js +++ b/lib/pack.js @@ -332,7 +332,7 @@ internals.Pack.prototype._require = function (name, permissions, options, callba itemName = callerPath + '/' + itemName; } else if (itemName[0] !== '/') { - itemName = require.main.paths[0] + '/' + itemName; + itemName = process.cwd() + '/node_modules/' + itemName; } var plugin = null; diff --git a/lib/server.js b/lib/server.js index 289967dab..f82089d0e 100755 --- a/lib/server.js +++ b/lib/server.js @@ -48,6 +48,9 @@ module.exports = internals.Server = function (/* host, port, options */) { var args = {}; for (var a = 0, al = arguments.length; a < al; ++a) { + if (arguments[a] === undefined) { + continue; + } var type = typeof arguments[a]; var key = argMap[type]; Utils.assert(key, 'Bad server constructor arguments: no match for arg type ' + type); diff --git a/package.json b/package.json index b46170dec..747e8d2d0 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "catbox": "0.1.x", "cryptiles": "0.1.x", "iron": "0.2.x", - "lru-cache": "2.2.x" + "lru-cache": "2.2.x", + "optimist": "0.3.x" }, "devDependencies": { "mocha": "1.x.x", @@ -44,7 +45,11 @@ "jade": "0.28.x", "blanket": "1.0.x", "travis-cov": "0.2.x", - "complexity-report": "0.x.x" + "complexity-report": "0.x.x", + "furball": "0.0.x" + }, + "bin": { + "hapi": "./bin/hapi" }, "scripts": { "test": "make test && make test-cov", diff --git a/test/integration/composer.js b/test/integration/composer.js new file mode 100755 index 000000000..77ea88989 --- /dev/null +++ b/test/integration/composer.js @@ -0,0 +1,66 @@ +// Load modules + +var Chai = require('chai'); +var Hapi = require('../helpers'); + + +// Declare internals + +var internals = {}; + + +// Test shortcuts + +var expect = Chai.expect; + + +describe('Composer', function () { + + it('composes pack', function (done) { + + var options = [{ + servers: { + ren: { + port: 0, + labels: ['api', 'nasty'], + config: { + monitor: { + subscribers: { + console: ['ops', 'request', 'log'] + } + }, + cache: 'redis' + } + }, + stimpy: { + host: 'localhost', + port: 0, + labels: ['api', 'nice'] + } + }, + plugins: { + furball: { + version: false, + plugins: '/' + } + } + }]; + + var composer = new Hapi.Composer(options); + composer.compose(function (err) { + + expect(err).to.not.exist; + composer.start(function (err) { + + expect(err).to.not.exist; + composer.stop(); + + composer.packs[0].servers[0].inject({ method: 'GET', url: '/' }, function (res) { + + expect(res.result).to.deep.equal([{ "name": "furball", "version": "0.0.7" }]); + done(); + }); + }); + }); + }); +}); From dc0302ba7633c4015410d15852ad4ec5c8859b17 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 20 Feb 2013 12:27:33 -0800 Subject: [PATCH 2/2] composer permissions --- lib/composer.js | 5 ++++- test/integration/composer.js | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/composer.js b/lib/composer.js index 10a829ac4..19f48a32f 100755 --- a/lib/composer.js +++ b/lib/composer.js @@ -36,6 +36,9 @@ var options = [{ version: false, plugins: '/' } + }, + permissions: { + ext: true } }]; */ @@ -81,7 +84,7 @@ internals.Composer.prototype.compose = function (callback) { Async.forEachSeries(sets, function (set, next) { - set.pack.require(set.plugins, next); + set.pack.allow(set.permissions || {}).require(set.plugins, next); }, function (err) { diff --git a/test/integration/composer.js b/test/integration/composer.js index 77ea88989..589aebaab 100755 --- a/test/integration/composer.js +++ b/test/integration/composer.js @@ -18,7 +18,7 @@ describe('Composer', function () { it('composes pack', function (done) { - var options = [{ + var options = { servers: { ren: { port: 0, @@ -43,8 +43,11 @@ describe('Composer', function () { version: false, plugins: '/' } + }, + permissions: { + ext: true } - }]; + }; var composer = new Hapi.Composer(options); composer.compose(function (err) {