├── index.js ├── .coveralls.yml ├── .travis.yml ├── .gitignore ├── package.json ├── .jshintrc ├── Gruntfile.js ├── README.MD ├── lib └── index.js └── test └── specs.js /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib'); -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-pro 2 | repo_token: UguHiPXFC3HM8BdI3R5FC9Cdi2aO5LLMe -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 0.10 5 | - 0.11 6 | before_install: npm install -g grunt-cli 7 | script: grunt test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 27 | node_modules -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hapi-rabbit", 3 | "version": "0.0.4", 4 | "description": "hapijs rabbitMQ plugin", 5 | "main": "index.js", 6 | "keywords": [ 7 | "hapi", 8 | "rabbit.js", 9 | "rabbitMQ", 10 | "event", 11 | "messageQueue", 12 | "messageBus" 13 | ], 14 | "dependencies": { 15 | "hapi": "^8.0.0", 16 | "hoek": "^2.10.0", 17 | "joi": "^5.0.2", 18 | "rabbit.js": "^0.4.2" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/aduis/hapi-rabbit.git" 23 | }, 24 | "author": "Andre Duis ", 25 | "contributors": [ 26 | { 27 | "name": "Markus Dethlefsen", 28 | "email": "hapi-rabbit@markus-inger.de" 29 | } 30 | ], 31 | "scripts": { 32 | "start": "node index.js" 33 | }, 34 | "license": "ISC", 35 | "devDependencies": { 36 | "assert": "^1.1.2", 37 | "chai": "^1.10.0", 38 | "coveralls": "^2.11.2", 39 | "grunt": "^0.4.5", 40 | "grunt-contrib-jshint": "^0.10.0", 41 | "grunt-contrib-watch": "~0.5.3", 42 | "grunt-includes": "~0.4.0", 43 | "grunt-mocha-cov": "^0.3.0", 44 | "grunt-mocha-istanbul": "^2.2.0", 45 | "grunt-mocha-test": "^0.12.4", 46 | "istanbul": "^0.3.5", 47 | "mocha": "^2.0.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "curly": false, 4 | "eqeqeq": true, 5 | "forin": true, 6 | "immed": true, 7 | "latedef": true, 8 | "newcap": true, 9 | "noarg": true, 10 | "noempty": true, 11 | "nonew": true, 12 | "plusplus": false, 13 | "strict": true, 14 | "trailing": true, 15 | "-W040": true, 16 | "asi": false, 17 | "boss": true, 18 | "debug": true, 19 | "eqnull": true, 20 | "esnext": false, 21 | "evil": false, 22 | "expr": true, 23 | "funcscope": false, 24 | "globalstrict": false, 25 | "iterator": false, 26 | "lastsemic": false, 27 | "laxbreak": true, 28 | "laxcomma": false, 29 | "loopfunc": true, 30 | "multistr": false, 31 | "proto": false, 32 | "scripturl": false, 33 | "smarttabs": false, 34 | "shadow": false, 35 | "sub": true, 36 | "supernew": false, 37 | "validthis": false, 38 | "browser": true, 39 | "couch": false, 40 | "devel": false, 41 | "dojo": false, 42 | "jquery": true, 43 | "mootools": false, 44 | "unused": false, 45 | "undef": false, 46 | "node": true, 47 | "nonstandard": true, 48 | "prototypejs": false, 49 | "rhino": false, 50 | "wsh": false, 51 | "nomen": false, 52 | "onevar": false, 53 | "passfail": false, 54 | "white": false, 55 | "es5": true, 56 | "-W117": true, 57 | "maxerr": 100, 58 | "predef": [ 59 | "console" 60 | ], 61 | "indent": 4 62 | } -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 3 | grunt.loadNpmTasks('grunt-contrib-watch'); 4 | grunt.loadNpmTasks('grunt-mocha-istanbul'); 5 | grunt.loadNpmTasks('grunt-contrib-jshint'); 6 | 7 | grunt.initConfig({ 8 | 9 | watch: { 10 | scripts: { 11 | files : ['./lib/**/*.js', './test/**/*.js'], 12 | tasks : ['mocha_istanbul:coverage'], 13 | options: { 14 | debounceDelay: 250 15 | } 16 | } 17 | }, 18 | 19 | mocha_istanbul: { 20 | coverage : { 21 | src : 'test', 22 | options: { 23 | mask: '*.js' 24 | } 25 | }, 26 | coveralls: { 27 | src: ['test'], 28 | options: { 29 | coverage:true, 30 | check: { 31 | lines: 75, 32 | statements: 75 33 | }, 34 | root: './lib', // define where the cover task should consider the root of libraries that are covered by tests 35 | reportFormats: ['cobertura','lcovonly'] 36 | } 37 | } 38 | }, 39 | 40 | jshint: { 41 | all: ['Gruntfile.js', 'lib/**/*.js', 'test/**/*.js'] 42 | } 43 | 44 | }); 45 | 46 | grunt.event.on('coverage', function(lcov, done){ 47 | require('coveralls').handleInput(lcov, function(err){ 48 | if (err) { 49 | return done(err); 50 | } 51 | done(); 52 | }); 53 | }); 54 | 55 | grunt.registerTask('test', [ 'jshint:all', 'mocha_istanbul:coveralls' ]); 56 | 57 | }; -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # hapi-rabbit 2 | A simple hapijs plugin to connect to rabbitMQ 3 | 4 | [![Build Status](https://travis-ci.org/aduis/hapi-rabbit.svg?branch=master)](https://travis-ci.org/aduis/hapi-rabbit) [![Coverage Status](https://img.shields.io/coveralls/aduis/hapi-rabbit.svg)](https://coveralls.io/r/aduis/hapi-rabbit?branch=master) [![npm version](https://badge.fury.io/js/hapi-rabbit.svg)](http://badge.fury.io/js/hapi-rabbit) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) 5 | 6 | [![NPM](https://nodei.co/npm/hapi-rabbit.png)](https://npmjs.org/package/hapi-rabbit) 7 | 8 | ## Introduction 9 | hapi-rabbit basically wraps rabbit.js and gives the user a simple api to publish and subscribe to rabbitMQ 10 | 11 | ## Prerequisites 12 | * RabbitMQ 13 | * Node.js 14 | * Hapi.js 15 | 16 | ## Installation 17 | ```javascript 18 | npm install hapi-rabbit --save 19 | ``` 20 | * add plugin to hapi server 21 | * include in your code 22 | 23 | ## Examples 24 | ### load plugin 25 | ```javascript 26 | server.register([ 27 | { 28 | register: require('hapi-rabbit'), 29 | options: { 30 | url: 'amqp://localhost' 31 | } 32 | } 33 | ], function (err) { 34 | if (err) { 35 | throw err; 36 | } 37 | }); 38 | ``` 39 | ### publish a message 40 | ```javascript 41 | function (request, reply) { 42 | 43 | var rabbit = request.server.plugins['hapi-rabbit']; 44 | rabbit.createContext(function(err, context){ 45 | if(err){ 46 | console.log('err', err); 47 | } 48 | 49 | rabbit.publish(context, 'exchange', 'messageType', 'message', function(err, data){ 50 | console.log('messageObject', data); 51 | }); 52 | }); 53 | 54 | reply('Hello!'); 55 | } 56 | ``` 57 | ### subscribe 58 | ```javascript 59 | 60 | var Hapi = require('hapi'); 61 | var server = new Hapi.Server(); 62 | var hapiRabbit = require('hapi-rabbit'); 63 | 64 | server.connection( 65 | { 66 | port: "9090" 67 | } 68 | ); 69 | 70 | var plugins = [{ 71 | register: hapiRabbit, 72 | options: { 73 | url: "amqp://localhost" 74 | } 75 | }]; 76 | 77 | server.register(plugins, function (err) { 78 | if (err) { 79 | console.log('error when registering modules', error); 80 | } 81 | }); 82 | 83 | server.start(function (err) { 84 | if (err) { 85 | console.log('error when starting server', error); 86 | } 87 | 88 | var rabbit = server.plugins['hapi-rabbit']; 89 | rabbit.createContext(function(err, context){ 90 | if(err){ 91 | console.log('err', err); 92 | } 93 | 94 | rabbit.subscribe(context, 'exchange', function(err, message){ 95 | console.log('message', message); 96 | }); 97 | }); 98 | 99 | console.log('service started'); 100 | }); 101 | 102 | ``` 103 | ## Contribute 104 | If you want to contribute to hapi-rabbit, please send me a pull request. 105 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var rabbitjs = require('rabbit.js'); 2 | var Hoek = require('hoek'); 3 | var Joi = require('joi'); 4 | 5 | module.exports.register = function (plugin, userOptions, next) { 6 | 7 | var defaultOptions = { 8 | url : "amqp://localhost", 9 | routing : 'topic', 10 | encoding: 'utf8', 11 | extras: {} 12 | }; 13 | 14 | var options = Hoek.applyToDefaults(defaultOptions, userOptions); 15 | 16 | plugin.expose('subscribe', function (context, exchange, callback) { 17 | 18 | Joi.validate(exchange, Joi.string().alphanum(), function (err) { 19 | 20 | if (err === null) { //exchange is valid 21 | 22 | var sub = context.socket('SUB', {routing: options.routing}); 23 | 24 | sub.connect(exchange, exchange + '.*', function () { 25 | sub.setEncoding(options.encoding); 26 | 27 | sub.on('data', function (message) { 28 | callback(null, JSON.parse(message)); 29 | }); 30 | }); 31 | 32 | } else { 33 | 34 | callback(err, null); 35 | 36 | } 37 | 38 | }); 39 | 40 | }); 41 | 42 | plugin.expose('publish', function (context, exchange, messageType, message, callback) { 43 | 44 | var paramSchema = Joi.object().keys({ 45 | exchange : Joi.string().alphanum().required(), 46 | messageType: Joi.string().alphanum().required() 47 | }); 48 | 49 | Joi.validate({ exchange: exchange, messageType: messageType }, paramSchema, function (err) { 50 | 51 | if (err === null) { //exchange is valid 52 | 53 | var pub = context.socket('PUB', {routing: options.routing}); 54 | 55 | var messageObject = { 56 | type: messageType, 57 | data: message 58 | }; 59 | 60 | pub.connect(exchange, function () { 61 | if(options.hasOwnProperty('extras')) { 62 | for (var key in options.extras) { 63 | pub.setsockopt(key, options.extras[key]); 64 | } 65 | } 66 | 67 | pub.publish(exchange + '.' + messageType, JSON.stringify(messageObject)); 68 | callback(null, messageObject); 69 | }); 70 | 71 | } else { 72 | 73 | callback(err, null); 74 | 75 | } 76 | }); 77 | }); 78 | 79 | plugin.expose('createContext', function (callback) { 80 | 81 | var context = rabbitjs.createContext(options.url); 82 | 83 | context.on('ready', function () { 84 | callback(null, context); 85 | }); 86 | 87 | context.on('error', function (err) { 88 | callback(err, null); 89 | }); 90 | 91 | }); 92 | 93 | next(); 94 | }; 95 | 96 | module.exports.register.attributes = { 97 | pkg: require('../package.json') 98 | }; 99 | -------------------------------------------------------------------------------- /test/specs.js: -------------------------------------------------------------------------------- 1 | var should = require('chai').should(); 2 | var Hapi = require("hapi"); 3 | var hapiRabbit = require('../lib'); 4 | 5 | var setup = function (callback) { 6 | 7 | var server = new Hapi.Server(); 8 | server.register({ 9 | register: hapiRabbit 10 | }, function (err) { 11 | 12 | if (err) { 13 | console.log('Failed loading plugin'); 14 | } 15 | 16 | var rabbit = server.plugins['hapi-rabbit']; 17 | 18 | var result = { 19 | rabbit: rabbit, 20 | server: server 21 | }; 22 | 23 | callback(null, result); 24 | }); 25 | 26 | }; 27 | 28 | var context = { 29 | socket: function (type) { 30 | var connect = false; 31 | 32 | if (type === 'SUB') { 33 | connect = function (exchange, messageType, callback) { 34 | callback(); 35 | }; 36 | } else if (type === 'PUB') { 37 | connect = function (exchange, callback) { 38 | callback(); 39 | }; 40 | } 41 | 42 | return { 43 | connect : connect, 44 | publish : function () { 45 | }, 46 | setEncoding: function () { 47 | }, 48 | on : function (event, callback) { 49 | callback('{"type":"messageType","data":"message"}'); 50 | } 51 | }; 52 | } 53 | }; 54 | 55 | describe('hapiRabbit', function () { 56 | 57 | describe('plugin', function () { 58 | var server = null; 59 | var rabbit = null; 60 | 61 | beforeEach(function (done) { 62 | setup(function (err, result) { 63 | server = result.server; 64 | rabbit = result.rabbit; 65 | done(); 66 | }); 67 | }); 68 | 69 | it('should be defined', function () { 70 | rabbit.should.be.an('object'); 71 | }); 72 | 73 | it('should have subscribe function', function () { 74 | rabbit.should.respondTo('subscribe'); 75 | }); 76 | 77 | it('should have publish function', function () { 78 | rabbit.should.respondTo('publish'); 79 | }); 80 | 81 | it('should have createContext function', function () { 82 | rabbit.should.respondTo('createContext'); 83 | }); 84 | 85 | }); 86 | 87 | describe('subscribe invalid exchange', function () { 88 | var error = null; 89 | 90 | beforeEach(function (done) { 91 | 92 | setup(function (err, result) { 93 | result.rabbit.subscribe(context, 'exchange.bla', function (err) { 94 | error = err; 95 | done(); 96 | }); 97 | }); 98 | 99 | }); 100 | 101 | it('should return validation error when entering non-alphanumeric value', function () { 102 | error.name.should.equal('ValidationError'); 103 | }); 104 | 105 | }); 106 | 107 | describe('publish invalid exchange', function () { 108 | var error = null; 109 | 110 | beforeEach(function (done) { 111 | 112 | setup(function (err, result) { 113 | result.rabbit.publish(context, 'exchange.bla', 'messageType', 'message', function (err) { 114 | error = err; 115 | done(); 116 | }); 117 | }); 118 | 119 | }); 120 | 121 | it('should return validation error when entering non-alphanumeric value', function () { 122 | error.name.should.equal('ValidationError'); 123 | }); 124 | 125 | }); 126 | 127 | describe('publish invalid messageType', function () { 128 | var error = null; 129 | 130 | beforeEach(function (done) { 131 | 132 | setup(function (err, result) { 133 | result.rabbit.publish(context, 'exchange', 'messageType.sdks', 'message', function (err) { 134 | error = err; 135 | done(); 136 | }); 137 | }); 138 | 139 | }); 140 | 141 | it('should return validation error when entering non-alphanumeric value', function () { 142 | error.name.should.equal('ValidationError'); 143 | }); 144 | 145 | }); 146 | 147 | describe('publish', function () { 148 | var msg = null; 149 | 150 | beforeEach(function (done) { 151 | 152 | setup(function (err, result) { 153 | result.rabbit.publish(context, 'exchange', 'messageType', 'message', function (err, message) { 154 | msg = message; 155 | done(); 156 | }); 157 | }); 158 | 159 | }); 160 | 161 | it('should return messageObject', function () { 162 | msg.should.be.an('object'); 163 | }); 164 | 165 | it('should return messageObject with messageType', function () { 166 | msg.type.should.equal('messageType'); 167 | }); 168 | 169 | it('should return messageObject with data', function () { 170 | msg.data.should.equal('message'); 171 | }); 172 | 173 | }); 174 | 175 | describe('subscribe', function () { 176 | var msg = null; 177 | 178 | beforeEach(function (done) { 179 | 180 | setup(function (err, result) { 181 | result.rabbit.subscribe(context, 'exchange', function (err, message) { 182 | msg = message; 183 | done(); 184 | }); 185 | }); 186 | 187 | }); 188 | 189 | it('should return messageObject', function () { 190 | msg.should.be.an('object'); 191 | }); 192 | 193 | it('should return messageObject with messageType', function () { 194 | msg.type.should.equal('messageType'); 195 | }); 196 | 197 | it('should return messageObject with data', function () { 198 | msg.data.should.equal('message'); 199 | }); 200 | 201 | }); 202 | 203 | }); --------------------------------------------------------------------------------