Jump To …

AmqpDsl.coffee

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 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)

      if queue.exchangeName
        queueRef.bind queue.exchangeName, queue.routingKey
      
      if queue.messageListener
        queueRef.subscribe queue.sOptions, queue.messageListener
      
      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)