amqp-dsl
Version:
Amqp-DSL - Fluent interface for node-amqp
218 lines (163 loc) • 5.21 kB
text/coffeescript
# Amqp-DSL - Fluent interface for node-amqp
async = require 'async'
IndexedList = require './IndexedList'
AmqpQueue = require './AmqpQueue'
AmqpExchange = require './AmqpExchange'
module.exports = class AmqpDsl
LISTENNERS =['error','close','ready']
## Public API
#### require('amqp-dsl').login
# * `login( options = {} )`
#
AmqpDsl.login = (opt = {}) ->
new AmqpDsl(opt)
constructor:(opt = {}) ->
# Defaults
@_login = ''
@_password = ''
@_host = ''
@_port = 5672
@_vhost = '/'
@_conn = null
@_callback = ->
# Constructor arguments
opt.login and (@_login = opt.login)
opt.password and (@_password = opt.password)
opt.host and (@_host = opt.host)
opt.port and (@_port = opt.port)
opt.vhost and (@_vhost = opt.vhost)
opt.login and (@_login = opt.login)
# Events
@_events = {}
# Exchanges
@_exchanges = new IndexedList()
# Queues
@_queues = new IndexedList()
#### .on
# * `on( event, listener )`
on:( event, listener ) ->
if !~LISTENNERS.indexOf(event)
throw new Error("Event '#{event}' is invalid")
@_events[event] = [] if(!@_events[event])
@_events[event].push(listener)
this
#### .exchange
# * `.exchange( name, options )`
# * `.exchange( name, callback(exchange) )`
# * `.exchange( name, options, callback(exchange) )`
exchange:( name, options, openCallback ) ->
@_exchanges.set(name, new AmqpExchange(name, options, openCallback))
this
#### .queue
# * `.queue( name, options )`
# * `.queue( name, callback(queue) )`
# * `.queue( name, options, callback(queue) )`
queue:( name, options, openCallback ) ->
@_queues.set(name, new AmqpQueue(name, options, openCallback))
this
#### .queue(...).subscribe
# * `.subscribe( callback(message, header, deliveryInfo) )`
# * `.subscribe( options, callback(message, header, deliveryInfo) )`
subscribe:( options, messageListener ) ->
queue = @_queues.last()
throw new Error("At least one queue must be declared") if !queue
queue.subscribe(options, messageListener)
this
#### .queue(...).bind
# * `.bind( name, routingKey )`
bind:( name, routingKey ) ->
queue = @_queues.last()
throw new Error("At least one queue must be declared") if !queue
queue.bind(name, routingKey)
this
#### .connect
# * `.connect( amqp, callback(err, amqp) )`
# * `.connect( callback(err, amqp) )`
#
# `amqp` parameter is an hashtable which contain
#
# queues:
# sampleQueue:[Amqp::Queue]
#
# exchanges:
# sampleExchange:[Amqp::Exchange]
#
# connection: [Amqp::Connection]
#
connect:(amqp, @_callback)->
if amqp is undefined
@_callback = ->
amqp = require 'amqp'
if typeof amqp is "function"
@_callback = amqp
amqp = require 'amqp'
@_connect(amqp)
null
## Private API
# Create the connection to amqp and bind events
_connect:(amqp) ->
# Create connection
@conn = amqp.createConnection({
host: @_host,
port: @_port,
login: @_login,
password: @_password,
vhost: @_vhost
})
# When the connection will be ready, connect the exchanges
@on 'ready', () => @_connectExchanges(@_connectQueues.bind(this))
# Set event listeners
@conn.on(event, @_getListenerFor(event)) for event of @_events
# Return a listener fonction for the event `event`.
_getListenerFor: (event) ->
if @_events[event].length == 1
return @_events[event][0]
else
return (args...) =>
listener.apply(null, args) for listener in @_events[event]
true
# Connect to exchanges
_connectExchanges:(next) ->
async.forEach @_exchanges.list(), @_connectExchange.bind(@), (err) =>
if err
throw new Error("Couldn't connect to the exchanges: #{err.message}")
return
next()
# Exchange connection iterator
_connectExchange:(exchange, callback) ->
@conn.exchange exchange.name, exchange.options, (exchangeRef) ->
exchange.ref = exchangeRef
exchange.openCallback(exchangeRef)
callback(null, true)
# Connect to queues
_connectQueues:() ->
async.forEach @_queues.list(), @_connectQueue.bind(@), (err) =>
if err
throw new Error("Couldn't connect to the queues: #{err.message}")
return
@_done()
# Queue connection iterator
_connectQueue:(queue, callback) ->
@conn.queue queue.name, queue.options, (queueRef) ->
queue.ref = queueRef
queue.openCallback(queueRef)
queue.bindTo.forEach((bind) ->
[exchange, routingKey] = bind
queueRef.bind exchange, routingKey
)
queue.listenTo.forEach((listen) ->
[option, listener] = listen
queueRef.subscribe option, listener
)
callback(null, true)
# When everything's connected, trigger the final callback
_done:() ->
msg =
queues : {}
exchanges : {}
connection : @conn
for k,v of @_queues.index()
msg.queues[k] = v.ref
for k,v of @_exchanges.index()
msg.exchanges[k] = v.ref
@_callback(null, msg)