├── .gitignore ├── CHANGES.md ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── client.api.test.js └── client.behavior.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .project 3 | .DS_Store 4 | *.sublime* 5 | *.seed 6 | *.log 7 | *.csv 8 | *.dat 9 | *.out 10 | *.pid 11 | *.swp 12 | *.swo 13 | *.iml 14 | node_modules 15 | generated-instructions.json 16 | checkstyle.xml 17 | loopback-boot-*.tgz 18 | /test/sandbox/ 19 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | 2016-05-06, Version 0.1.1 2 | ========================= 3 | 4 | * update copyright notices and license (Ryan Graham) 5 | 6 | * Refer to licenses with a link (Sam Roberts) 7 | 8 | * Use strongloop conventions for licensing (Sam Roberts) 9 | 10 | * deps: add missing dev dep strong-pubsub (Ryan Graham) 11 | 12 | * Update README.md (Rand McKinney) 13 | 14 | 15 | 2015-03-31, Version 0.1.0 16 | ========================= 17 | 18 | * First release! 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) IBM Corp. 2015. All Rights Reserved. 2 | Node module: strong-pubsub-redis 3 | This project is licensed under the MIT License, full text below. 4 | 5 | -------- 6 | 7 | MIT license 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # strong-pubsub-redis 2 | 3 | **[Redis](http://redis.io/) `Adapter` for strong-pubsub** 4 | 5 | ## Installation 6 | 7 | ``` 8 | $ npm install strong-pubsub-redis 9 | ``` 10 | 11 | ## Use 12 | 13 | ```js 14 | var Client = require('strong-pubsub'); 15 | var Adapter = require('strong-pubsub-redis'); 16 | 17 | var client = new Client({host: 'http://my.message-broker.com', port: 3000}, Adapter); 18 | 19 | client.publish('my topic', 'my message'); 20 | ``` 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015. All Rights Reserved. 2 | // Node module: strong-pubsub-redis 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | module.exports = Adapter; 7 | 8 | var redis = require("redis") 9 | var EventEmitter = require('events').EventEmitter; 10 | var inherits = require('util').inherits; 11 | var debug = require('debug')('strong-pubsub:redis'); 12 | var defaults = require('lodash').defaults; 13 | 14 | function noop() {}; 15 | 16 | /** 17 | * The **Redis** `Adapter`. 18 | * 19 | * @class 20 | */ 21 | 22 | function Adapter(client) { 23 | var adapter = this; 24 | this.client = client; 25 | var options = this.options = client.options; 26 | } 27 | 28 | inherits(Adapter, EventEmitter); 29 | 30 | Adapter.prototype.connect = function(cb) { 31 | var adapter = this; 32 | var client = this.client; 33 | var options = this.options; 34 | var pubClient = this.redisPubClient = redis.createClient( 35 | this.options.port, 36 | this.options.host, 37 | this.options.redis 38 | ); 39 | var subClient = this.redisSubClient = redis.createClient( 40 | this.options.port, 41 | this.options.host, 42 | this.options.redis 43 | ); 44 | 45 | var connacks = 0; 46 | var clients = this.clients = new EventEmitter(); 47 | 48 | subClient.once('connect', onConnect); 49 | pubClient.once('connect', onConnect); 50 | pubClient.on('error', clients.emit.bind(clients, 'error')); 51 | subClient.on('error', clients.emit.bind(clients, 'error')); 52 | 53 | function onConnect() { 54 | connacks++; 55 | if(connacks === 2) { 56 | clients.emit('connect'); 57 | } 58 | } 59 | 60 | this.clients.once('connect', function() { 61 | adapter.clients.removeListener('error', cb); 62 | cb(); 63 | }); 64 | 65 | this.clients.once('error', cb); 66 | 67 | subClient.on('message', function(topic, message, options) { 68 | client.emit('message', topic, message, options); 69 | }); 70 | } 71 | 72 | Adapter.prototype.end = function(cb) { 73 | this.pubClient.end(); 74 | this.subClient.end(); 75 | } 76 | 77 | /** 78 | * Publish a `message` to the specified `topic`. 79 | * 80 | * @param {String} topic The topic to publish to. 81 | * @param {String|Buffer} message The message to publish to the topic. 82 | * @param {Object} [options] Additional options that are not required for publishing a message. 83 | * @param {Number} [options.qos] **default: `0`** The **MQTT** QoS (Quality of Service) setting. 84 | * @param {Boolean} [options.retain] **default: `false`** The `MQTT` retain setting. Whether or not the message should be retained. 85 | * 86 | * **Supported Values** 87 | * 88 | * - `0` - Just as reliable as TCP. Adapter will not get any missed messages (while it was disconnected). 89 | * - `1` - Adapter receives missed messages at least once and sometimes more than once. 90 | * - `2` - Adapter receives missed messages only once. 91 | * 92 | * @callback {Function} callback Called once the adapter has successfully finished publishing the message. 93 | * @param {Error} err An error object is included if an error was supplied by the adapter. 94 | */ 95 | 96 | Adapter.prototype.publish = function(topic, message, options, cb) { 97 | this.redisPubClient.publish(topic, message, cb); 98 | } 99 | 100 | /** 101 | * Subscribe to the specified `topic` or **topic pattern**. 102 | * 103 | * @param {String} topic The topic to subscribe to. 104 | * @param {Object} options The MQTT specific options. 105 | * @param {Object} options.qos See `publish()` for `options.qos`. 106 | * 107 | * @callback {Function} callback Called once the adapter has finished subscribing. 108 | * @param {Error} err An error object is included if an error was supplied by the adapter. 109 | * @param {Object[]} granted An array of topics granted formatted as an object `{topic: 't', qos: n}`. 110 | * @param {String} granted[n].topic The topic granted 111 | * @param {String} granted[n].qos The qos for the topic 112 | */ 113 | 114 | Adapter.prototype.subscribe = function(topic, options, cb) { 115 | this.redisSubClient.subscribe(topic, cb); 116 | } 117 | 118 | /** 119 | * Unsubscribe from the specified `topic` or **topic pattern**. 120 | * 121 | * @param {String} topic The topic or **topic pattern** to unsubscribe. 122 | * @callback {Function} callback Called once the adapter has finished unsubscribing. 123 | * @param {Error} err An error object is included if an error was supplied by the adapter. 124 | */ 125 | 126 | Adapter.prototype.unsubscribe = function(topic, cb) { 127 | this.redisSubClient.unsubscribe(topic, cb); 128 | } 129 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "strong-pubsub-redis", 3 | "version": "0.1.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "author": "Ritchie Martori", 10 | "license": "MIT", 11 | "dependencies": { 12 | "debug": "^2.1.1", 13 | "lodash": "^3.3.1", 14 | "redis": "^0.12.1" 15 | }, 16 | "devDependencies": { 17 | "chai": "^2.1.0", 18 | "mocha": "^2.0.0", 19 | "strong-pubsub": "^0.2.0", 20 | "strong-pubsub-test": "^0.1.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/client.api.test.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015. All Rights Reserved. 2 | // Node module: strong-pubsub-redis 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | var helpers = require('strong-pubsub-test'); 7 | var getPort = helpers.getFreePort; 8 | var defineClientTests = helpers.defineClientTests; 9 | var usingRedis = helpers.usingRedis; 10 | var Client = require('strong-pubsub'); 11 | var Adapter = require('../'); // strong-pubsub-redis 12 | 13 | describe('Redis', function () { 14 | beforeEach(function(done) { 15 | var test = this; 16 | usingRedis(function(err, port, redis) { 17 | test.port = port; 18 | test.redis = redis; 19 | done(err); 20 | }); 21 | }); 22 | 23 | afterEach(function (done) { 24 | if(this.redis) { 25 | this.redis.kill('SIGINT'); 26 | done(); 27 | } else { 28 | done(); 29 | } 30 | }); 31 | 32 | defineClientTests(Client, Adapter); 33 | }); 34 | -------------------------------------------------------------------------------- /test/client.behavior.test.js: -------------------------------------------------------------------------------- 1 | // Copyright IBM Corp. 2015. All Rights Reserved. 2 | // Node module: strong-pubsub-redis 3 | // This file is licensed under the MIT License. 4 | // License text available at https://opensource.org/licenses/MIT 5 | 6 | var Client = require('strong-pubsub'); 7 | var Adapter = require('../'); // strong-pubsub-redis 8 | var helpers = require('strong-pubsub-test'); 9 | var defineClientBehaviorTests = helpers.defineClientBehaviorTests; 10 | var usingRedis = helpers.usingRedis; 11 | 12 | describe('redis client behavior', function () { 13 | beforeEach(function(done) { 14 | var test = this; 15 | usingRedis(function(err, port, redis) { 16 | test.port = port; 17 | test.redis = redis; 18 | done(err); 19 | }); 20 | }); 21 | 22 | afterEach(function (done) { 23 | if(this.redis) { 24 | this.redis.kill('SIGINT'); 25 | done(); 26 | } else { 27 | done(); 28 | } 29 | }); 30 | 31 | defineClientBehaviorTests(Client, Adapter); 32 | }); 33 | --------------------------------------------------------------------------------