149 lines
2.6 KiB
JavaScript
149 lines
2.6 KiB
JavaScript
|
|
||
|
/**
|
||
|
* Module dependencies.
|
||
|
*/
|
||
|
|
||
|
var debug = require('debug')('axon:sub');
|
||
|
var escape = require('escape-string-regexp');
|
||
|
var Message = require('amp-message');
|
||
|
var Socket = require('./sock');
|
||
|
|
||
|
/**
|
||
|
* Expose `SubSocket`.
|
||
|
*/
|
||
|
|
||
|
module.exports = SubSocket;
|
||
|
|
||
|
/**
|
||
|
* Initialize a new `SubSocket`.
|
||
|
*
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
function SubSocket() {
|
||
|
Socket.call(this);
|
||
|
this.subscriptions = [];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Inherits from `Socket.prototype`.
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.__proto__ = Socket.prototype;
|
||
|
|
||
|
/**
|
||
|
* Check if this socket has subscriptions.
|
||
|
*
|
||
|
* @return {Boolean}
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.hasSubscriptions = function(){
|
||
|
return !! this.subscriptions.length;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Check if any subscriptions match `topic`.
|
||
|
*
|
||
|
* @param {String} topic
|
||
|
* @return {Boolean}
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.matches = function(topic){
|
||
|
for (var i = 0; i < this.subscriptions.length; ++i) {
|
||
|
if (this.subscriptions[i].test(topic)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Message handler.
|
||
|
*
|
||
|
* @param {net.Socket} sock
|
||
|
* @return {Function} closure(msg, mulitpart)
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.onmessage = function(sock){
|
||
|
var subs = this.hasSubscriptions();
|
||
|
var self = this;
|
||
|
|
||
|
return function(buf){
|
||
|
var msg = new Message(buf);
|
||
|
|
||
|
if (subs) {
|
||
|
var topic = msg.args[0];
|
||
|
if (!self.matches(topic)) return debug('not subscribed to "%s"', topic);
|
||
|
}
|
||
|
|
||
|
self.emit.apply(self, ['message'].concat(msg.args).concat(sock));
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Subscribe with the given `re`.
|
||
|
*
|
||
|
* @param {RegExp|String} re
|
||
|
* @return {RegExp}
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.subscribe = function(re){
|
||
|
debug('subscribe to "%s"', re);
|
||
|
this.subscriptions.push(re = toRegExp(re));
|
||
|
return re;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Unsubscribe with the given `re`.
|
||
|
*
|
||
|
* @param {RegExp|String} re
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.unsubscribe = function(re){
|
||
|
debug('unsubscribe from "%s"', re);
|
||
|
re = toRegExp(re);
|
||
|
for (var i = 0; i < this.subscriptions.length; ++i) {
|
||
|
if (this.subscriptions[i].toString() === re.toString()) {
|
||
|
this.subscriptions.splice(i--, 1);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Clear current subscriptions.
|
||
|
*
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.clearSubscriptions = function(){
|
||
|
this.subscriptions = [];
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Subscribers should not send messages.
|
||
|
*/
|
||
|
|
||
|
SubSocket.prototype.send = function(){
|
||
|
throw new Error('subscribers cannot send messages');
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Convert `str` to a `RegExp`.
|
||
|
*
|
||
|
* @param {String} str
|
||
|
* @return {RegExp}
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
function toRegExp(str) {
|
||
|
if (str instanceof RegExp) return str;
|
||
|
str = escape(str);
|
||
|
str = str.replace(/\\\*/g, '(.+)');
|
||
|
return new RegExp('^' + str + '$');
|
||
|
}
|