node-busmq
Version:
A high performance, highly-available and scalable, message bus and queueing system for node.js backed by Redis
160 lines (137 loc) • 3.66 kB
JavaScript
var events = require('events');
var util = require('util');
/**
* Pubsub. Do not instantiate directly, instead use {Bus#pubsub} to create a new Pubsub.
* @param bus
* @param name
* @constructor
*/
function Pubsub(bus, name) {
events.EventEmitter.call(this);
this.bus = bus;
this.type = 'pubsub';
this.id = "bus:pubsub:" + name;
this.logger = bus.logger.withTag(this.id);
this.name = name;
}
util.inherits(Pubsub, events.EventEmitter);
/**
* Setup association to the connection
* @private
*/
Pubsub.prototype._connect = function() {
if (this.connection) {
return this.connection;
}
// always use the first connection for pubsub
this.connection = this.bus._connectionOne();
if (!this.connection) {
this.emit('error', 'no connection available');
return null;
}
return this.connection;
};
/**
* Subscribe to the pubsub channel.
* Messages arriving on the pubsub channel will be emitted through the 'message' event.
*/
Pubsub.prototype.subscribe = function() {
if (this.isSubscribed()) {
return;
}
var _this = this;
var connection = this._connect();
if (!connection) {
return;
}
this.subscribed = true;
this._subscribeEvent = function(type, channel, message) {
switch (type) {
case 'subscribe':
_this.emit('subscribed');
break;
case 'unsubscribe':
_this.emit('unsubscribed');
break;
case 'message':
if (channel !== _this.id) {
_this.emit('error', 'received message from unsubscribed channel ' + channel);
return;
}
_this.emit('message', message);
break;
}
};
this.bus._subscribe(connection, this.id, this._subscribeEvent);
};
Pubsub.prototype.attach = Pubsub.prototype.subscribe;
/**
* Unsubscribe from receiving messages
*/
Pubsub.prototype.unsubscribe = function() {
if (!this.isSubscribed()) {
return;
}
if (!this.connection) {
return;
}
this.subscribed = false;
this.bus._unsubscribe(this.connection, this.id, this._subscribeEvent);
delete this._subscribeEvent;
};
/**
* Returns whether this pubsub is subscribed on the pubsub channel to receive messages
*/
Pubsub.prototype.isSubscribed = function() {
return this.subscribed;
};
/**
* Publish a message on the pubsub channel
*/
Pubsub.prototype.publish = function(message, cb) {
var _this = this;
var connection = this._connect();
if (!connection) {
return;
}
if (typeof message === 'object') {
message = JSON.stringify(message);
}
connection.publish(_this.id, message, function(err) {
if (err) {
if (cb) {
cb(err);
} else {
_this.emit('error', "error publishing message: " + err);
}
return;
}
cb && cb();
});
};
/**
* Unsubscribe and close this pubsub instance
*/
Pubsub.prototype.detach = function() {
if (this.isSubscribed()) {
this.unsubscribe();
}
if (this.connection) {
this.connection.emit('detach:' + this.id);
}
};
/**
* Convert all eligible methods into promise based methods instead of callback based methods
*/
Pubsub.prototype.promisify = function() {
return this.bus.promisify(this, ["publish"]);
};
/**
* Tells the federation object which methods save state that need to be restored upon
* reconnecting over a dropped websocket connection
* @private
*/
Pubsub.prototype._federationState = function() {
return [{save: 'subscribe', unsave: 'unsubscribe'}];
};
exports = module.exports = Pubsub;