You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
6.3 KiB
214 lines
6.3 KiB
"use strict"; |
|
|
|
var EventEmitter = require('events').EventEmitter; |
|
|
|
/** |
|
* An `AbstractAscoltatore` is a class that inherits from `EventEmitter`. |
|
* It is also the base class of `ascoltatori`. It is not meant to be used alone, |
|
* but it defines the interface for every ascoltatore. |
|
* |
|
* Every ascoltatore emits the following events: |
|
* - `ready`, when the ascolatore is ready for subscribing and/or |
|
* publishing messages; |
|
* - `closed`, when the ascoltatore has closed all the connections |
|
* and therefore it cannot accept new messages; |
|
* - `error`, if something goes wrong. |
|
* |
|
* @api public |
|
*/ |
|
function AbstractAscoltatore(settings, nativeSettings) { |
|
EventEmitter.call(this); |
|
|
|
settings = settings || {}; |
|
nativeSettings = nativeSettings || {}; |
|
|
|
this._separator = settings.separator || '/', |
|
this._wildcardOne = settings.wildcardOne || '+', |
|
this._wildcardSome = settings.wildcardSome || '*'; |
|
this._nativeSettings = nativeSettings; |
|
|
|
if (nativeSettings.separator && |
|
(this._separator !== nativeSettings.separator)) { |
|
this._reInSeparator = new RegExp('\\' + this._separator, 'g'); |
|
this._reOutSeparator = new RegExp('\\' + nativeSettings.separator, 'g'); |
|
} |
|
if (nativeSettings.wildcardOne && |
|
(this._wildcardOne !== nativeSettings.wildcardOne)) { |
|
this._reInWildcardOne = new RegExp('\\' + this._wildcardOne, 'g'); |
|
} |
|
if (nativeSettings.wildcardSome && |
|
(this._wildcardSome !== nativeSettings.wildcardSome)) { |
|
this._reInWildcardSome = new RegExp('\\' + this._wildcardSome, 'g'); |
|
} |
|
|
|
this._setPublish(); |
|
|
|
this._ready = false; |
|
this._closed = false; |
|
|
|
var that = this; |
|
|
|
this.on("ready", function() { |
|
that._ready = true; |
|
}); |
|
|
|
this.on("closed", function() { |
|
that._closed = true; |
|
}); |
|
|
|
this.on("newListener", function(event, listener) { |
|
if (event === "ready" && that._ready) { |
|
listener(); |
|
} |
|
}); |
|
|
|
this.setMaxListeners(0); |
|
} |
|
|
|
AbstractAscoltatore.prototype = Object.create(EventEmitter.prototype); |
|
|
|
AbstractAscoltatore.prototype._raiseIfClosed = function raiseIfClosed() { |
|
if (this._closed) { |
|
throw new Error("This ascoltatore is closed"); |
|
} |
|
}; |
|
|
|
/** |
|
* This method provides a way for users to subscribe for messages. |
|
* |
|
* The messages are published on topics, that is just a "path", e.g. |
|
* `/this/is/a/topic`. |
|
* The topic are organized in a hierarchy, and `subscribe` support the usage |
|
* of wildcards, e.g. you can subscribe to `*` and it will |
|
* match all the topics |
|
* |
|
* Example: |
|
* ascoltatore.subscribe("*", function () { |
|
* // this will print { '0': "hello/42", '1': "a message" } |
|
* console.log(arguments); |
|
* }); |
|
* |
|
* @param {String} topic the topic to subscribe to |
|
* @param {Function} callback the callback that will be called when a new message is published. |
|
* @param {Function} done the callback that will be called when the subscribe is completed |
|
* @api public |
|
*/ |
|
AbstractAscoltatore.prototype.subscribe = function(topic, callback, done) { |
|
throw new Error("Subclass to implement"); |
|
}; |
|
|
|
/** |
|
* This method allow publishing of messages to topics. |
|
* |
|
* Example: |
|
* ascoltatore.publish("hello/42", "a message", function () { |
|
* console.log("message published"); |
|
* }); |
|
* |
|
* |
|
* @param {String} topic the topic to publish to |
|
* @param {Object} payload the callback that will be called when a new message is published. |
|
* @param {Object} options (optional) Metadata associated with the message (e.g. qos, messageId). If you only specify 3 parameters to your method then you won't be passed this parameter. |
|
* @param {Function} done the callback that will be called after the message has been published. |
|
* @api public |
|
*/ |
|
AbstractAscoltatore.prototype.publish = function(topic, payload, options, done) { |
|
throw new Error("Subclass to implement"); |
|
}; |
|
|
|
AbstractAscoltatore.prototype._setPublish = function() { |
|
var proto = Object.getPrototypeOf(this), |
|
f = proto.publish, |
|
publish, |
|
newPublish; |
|
|
|
if (!f) { return; } |
|
|
|
if (f.length === 4) { |
|
publish = this.publish; |
|
} else { |
|
publish = function (topic, payload, options, done) { |
|
return f.call(this, topic, payload, done); |
|
}; |
|
} |
|
|
|
newPublish = function (topic, payload, options, done) { |
|
if ((typeof options === 'function') || |
|
(done && (typeof done !== 'function'))) { |
|
done = options; |
|
options = {}; |
|
} else if ((options === undefined) || (options === null)) { |
|
options = {}; |
|
} |
|
|
|
return publish.call(this, topic, payload, options, done); |
|
}; |
|
|
|
this.publish = newPublish; |
|
|
|
if (proto.pub === proto.publish) { |
|
this.pub = newPublish; |
|
} |
|
}; |
|
|
|
/** |
|
* This method provides the inverse of subscribe. |
|
* |
|
* @param {String} topic the topic from which to unsubscribe |
|
* @param {Function} callback the callback that will be unsubscribed |
|
* @param {Function} done the callback that will be called when the unsubscribe is completed |
|
* @api public |
|
*/ |
|
AbstractAscoltatore.prototype.unsubscribe = function(topic, callback, done) { |
|
throw new Error("Subclass to implement"); |
|
}; |
|
|
|
/** |
|
* This method closes the Ascoltatore. |
|
* After this method is called every call to subscribe or publish will raise |
|
* an exception |
|
* |
|
* @param {Function} done the callback that will be called when Ascoltatore is closed |
|
* @api public |
|
*/ |
|
AbstractAscoltatore.prototype.close = function(done) { |
|
throw new Error("Subclass to implement"); |
|
}; |
|
|
|
AbstractAscoltatore.prototype._subTopic = function(topic) { |
|
if (this._reInSeparator) { |
|
topic = topic.replace(this._reInSeparator, |
|
this._nativeSettings.separator); |
|
} |
|
if (this._reInWildcardSome) { |
|
topic = topic.replace(this._reInWildcardSome, |
|
this._nativeSettings.wildcardSome); |
|
} |
|
if (this._reInWildcardOne) { |
|
topic = topic.replace(this._reInWildcardOne, |
|
this._nativeSettings.wildcardOne); |
|
} |
|
return topic; |
|
}; |
|
|
|
AbstractAscoltatore.prototype._recvTopic = function(topic) { |
|
if (this._reOutSeparator) { |
|
topic = topic.replace(this._reOutSeparator, this._separator); |
|
} |
|
return topic; |
|
}; |
|
|
|
AbstractAscoltatore.prototype._pubTopic = function(topic) { |
|
if (this._reInSeparator) { |
|
topic = topic.replace(this._reInSeparator, |
|
this._nativeSettings.separator); |
|
} |
|
return topic; |
|
}; |
|
|
|
/** |
|
* Exports the AbstractAscoltatore; |
|
* |
|
* @api public |
|
*/ |
|
module.exports = AbstractAscoltatore;
|
|
|