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.
222 lines
5.7 KiB
222 lines
5.7 KiB
"use strict"; |
|
|
|
var util = require("./util"); |
|
var wrap = util.wrap; |
|
var defer = util.defer; |
|
var TrieAscoltatore = require("./trie_ascoltatore"); |
|
var AbstractAscoltatore = require('./abstract_ascoltatore'); |
|
var steed = require("steed")(); |
|
var SubsCounter = require("./subs_counter"); |
|
var debug = require("debug")("ascoltatori:amqplib"); |
|
|
|
/** |
|
* The AMQPAscoltatore is a class that inherits from AbstractAscoltatore. |
|
* It is backed by node-amqp. |
|
* It creates or use an exchange with the given name, using a "topic" topology. |
|
* It creates a single amqp queue for this process, in order to keep |
|
* the overhead low. |
|
* |
|
* It accepts these options: |
|
* - `client`, which is passed through to the amq.createConnection method; |
|
* - `exchange`, the exchange name; |
|
* - `amqp`, the amqp module (it will automatically be required if not present); |
|
* |
|
* @param {Object} opts The options for creating this ascoltatore. |
|
* @api public |
|
*/ |
|
|
|
function AMQPLibAscoltatore(opts) { |
|
AbstractAscoltatore.call(this, opts, { |
|
separator: '.', |
|
wildcardOne: '*', |
|
wildcardSome: '#' |
|
}); |
|
|
|
this._opts = opts || {}; |
|
this._opts.amqp = this._opts.amqp || require("amqplib/callback_api"); |
|
this._ascoltatore = new TrieAscoltatore(opts); |
|
|
|
this._subs_counter = new SubsCounter(); |
|
this._startConn(); |
|
} |
|
|
|
/** |
|
* The client connection decends from AbstractAscoltatore. |
|
* |
|
* @api private |
|
*/ |
|
AMQPLibAscoltatore.prototype = Object.create(AbstractAscoltatore.prototype); |
|
|
|
/** |
|
* Starts a new connection to an AMQP server. |
|
* Do nothing if it is already started. |
|
* |
|
* @api private |
|
*/ |
|
AMQPLibAscoltatore.prototype._startConn = function () { |
|
var conn = null, |
|
channel = null, |
|
that = this; |
|
|
|
if (this._client_conn === undefined) { |
|
|
|
var url = this._opts.url || 'amqp://127.0.0.1:5672'; |
|
|
|
var socketOptions = this._opts.socketOptions || {}; |
|
|
|
debug("connecting to " + this._opts.url); |
|
|
|
steed.series([ |
|
function (callback) { |
|
that._opts.amqp.connect(url, socketOptions, function (err, conn) { |
|
that._client_conn = conn; |
|
conn.on("error", function (error) { |
|
if (typeof error === 'string') { |
|
error = (new Error(error)); |
|
} |
|
|
|
that.emit("error", error); |
|
}); |
|
callback(); |
|
}); |
|
}, |
|
|
|
function (callback) { |
|
debug('connected'); |
|
that._client_conn.createChannel(function(err, channel){ |
|
that._channel = channel; |
|
that._channel.prefetch(42); // magic number? |
|
callback(); |
|
}); |
|
}, |
|
|
|
function(callback){ |
|
debug('channel created'); |
|
that._queue = util.buildIdentifier(); |
|
that._channel.assertQueue(that._queue, null, wrap(callback)); |
|
}, |
|
|
|
function (callback){ |
|
debug('queue created'); |
|
that._channel.assertExchange(that._opts.exchange, 'topic', {}, wrap(callback)); |
|
}, |
|
|
|
function (callback){ |
|
debug('exchange existed'); |
|
that._channel.consume(that._queue, function(msg){ |
|
that._channel.ack(msg); |
|
var topic = that._recvTopic(msg.fields.routingKey); |
|
debug("new message received from queue on topic " + topic); |
|
that._ascoltatore.publish(topic, msg.content.toString()); |
|
}, null, wrap(callback)); |
|
}, |
|
|
|
function (callback) { |
|
debug("subscribed to queue"); |
|
that.emit("ready"); |
|
callback(); |
|
} |
|
]); |
|
} |
|
return this._client_conn; |
|
}; |
|
|
|
AMQPLibAscoltatore.prototype.subscribe = function subscribe(topic, callback, done) { |
|
this._raiseIfClosed(); |
|
|
|
this._ascoltatore.subscribe(topic, callback); |
|
|
|
if (!this._subs_counter.include(topic)) { |
|
debug("binding queue to topic " + topic); |
|
|
|
this._channel.bindQueue(this._queue, this._opts.exchange, this._subTopic(topic), {}, function(err, ok){ |
|
debug("queue bound to topic " + topic); |
|
defer(done); |
|
}); |
|
} else { |
|
defer(done); |
|
} |
|
|
|
this._subs_counter.add(topic); |
|
|
|
debug("registered new subscriber for topic " + topic); |
|
}; |
|
|
|
AMQPLibAscoltatore.prototype.publish = function publish(topic, message, done) { |
|
this._raiseIfClosed(); |
|
|
|
debug("new message published to " + topic); |
|
|
|
this._channel.publish(this._opts.exchange, this._pubTopic(topic), new Buffer(String(message))); |
|
defer(done); |
|
}; |
|
|
|
AMQPLibAscoltatore.prototype.unsubscribe = function unsubscribe(topic, callback, done) { |
|
this._raiseIfClosed(); |
|
this._subs_counter.remove(topic); |
|
|
|
debug("deregistered subscriber for topic " + topic); |
|
|
|
this._ascoltatore.unsubscribe(topic, callback); |
|
|
|
if (!this._subs_counter.include(topic)) { |
|
this._channel.unbindQueue(this._queue, this._opts.exchange, this._subTopic(topic), {}, function(err, ok) { |
|
debug("queue unbound to topic " + topic); |
|
defer(done); |
|
}); |
|
} else { |
|
defer(done); |
|
} |
|
|
|
return this; |
|
}; |
|
|
|
AMQPLibAscoltatore.prototype.close = function close(done) { |
|
var that = this; |
|
|
|
if (this._closed) { |
|
wrap(done)(); |
|
return; |
|
} |
|
|
|
if (this._closing) { |
|
this.on("closed", done); |
|
return; |
|
} |
|
|
|
this._closing = true; |
|
|
|
if (this._client_conn !== undefined) { |
|
var doClose = function () { |
|
if (that._closed) { |
|
debug("closing twice, one was an error"); |
|
return; |
|
} |
|
|
|
debug("closed"); |
|
defer(done); |
|
that.emit("closed"); |
|
}; |
|
|
|
this._client_conn.on("close", doClose); |
|
this._channel.deleteQueue(this._queue); |
|
this._channel.close(); |
|
|
|
this._client_conn.close(); |
|
this._client_conn.removeAllListeners("error"); |
|
this._client_conn.on("error", doClose); |
|
|
|
delete this._client_conn; |
|
delete this._channel; |
|
delete this._queue; |
|
} |
|
}; |
|
|
|
util.aliasAscoltatore(AMQPLibAscoltatore.prototype); |
|
|
|
/** |
|
* Exports the AMQPAscoltatore |
|
* |
|
* @api public |
|
*/ |
|
module.exports = AMQPLibAscoltatore;
|
|
|