fanout/fanout_consumer.js

const MESSAGES = require('../internal').MESSAGES

/**
 * Create a consumer for an exchange of the fanout type.
 * Multiple fanout consumers can listen to a single fanout producer.
 * Init example:
 * <pre>
 *     const iamqp              = require('iamqp');
 *     const amqpUri            = 'amqp://localhost';
 *     const fanoutChannel      = 'fanout-channel-a';
 *     let fanoutConsumer       = new iamqp.FanoutConsumer(amqpUri, fanoutChannel);
 *
 *     // This needs to be done or the errors will bubble up.
 *     fanoutConsumer.getEventer().on('error', (err) => {
 *       console.log('fanout consumer error:' + err.message);
 *     });
 *
 *     // For when the connection is established.
 *     fanoutConsumer.getEventer().on('connected', () => {
 *       console.log('fanout consumer connected');
 *     });
 *
 *     // Get messages as fanout by the producer.
 *     fanoutConsumer.getEventer().on('message', (message) => {
 *       console.log('fanout consumer message:' + message);
 *     });
 *
 *     // Open the connection - this takes some time and is not sync
 *     fanoutConsumer.openConnection();
 *
 *     // ...
 *
 *     // Close the connection
 *     if (fanoutConsumer.closeConnection()) {
 *       console.log('fanout consumer connection closing ...');
 *     }
 * </pre>
 * ...
 */
class FanoutConsumer extends require('../common') {
  /**
   * @param {AmqpURI} amqpUri
   * @param {ChannelName} channelName
   * @param {Configuration} [configuration]
   */
  constructor (amqpUri, channelName, configuration) {
    super(amqpUri, channelName, configuration)
    this._name = `FANOUT-CONSUMER: ${this._configuration.channelName}`
    this._messageDispatcherWrapper('info', MESSAGES.INIT)

    // Common class performs the connection
    this._E.on('connected', () => {
      this._createChannel()
    })
  }

  /**
   * Create a channel and assert a fanout exchange.
   * @private
   */
  _createChannel () {
    this._amqp.connection.createChannel((channelCreatingErr, channelCreated) => {
      if (channelCreatingErr) {
        this._emitAndDispatchError(`${MESSAGES.CHANNEL_ERROR} -> ${channelCreatingErr.message}`)
        return
      }

      this._messageDispatcherWrapper('info', `${MESSAGES.CHANNEL_READY} -> ${MESSAGES.EXCHANGE_ASSERTING} -> ${MESSAGES.FANOUT}`)
      this._amqp.channel = channelCreated
      this._amqp.channel.assertExchange(this._configuration.channelName, 'fanout', {
        durable: false
      })

      this._assertQueue()
    })
  }

  /**
   * Assert the queue and bind the consumer function.
   * @private
   */
  _assertQueue () {
    this._amqp.channel.assertQueue('', {
      exclusive: true
    }, (assertQueueErr, assertedQueue) => {
      if (assertQueueErr) {
        this._emitAndDispatchError(`${MESSAGES.QUEUE_ASSERTING} -> ${assertQueueErr.message}`)
        return
      }

      this._messageDispatcherWrapper('info', `${MESSAGES.QUEUE_BIND} -> ${MESSAGES.CONSUMING}`)
      this._amqp.channel.bindQueue(assertedQueue.queue, this._configuration.channelName, '')
      this._amqp.channel.consume(assertedQueue.queue, (data) => {
        this._logData(data, 'consume')
        this._E.emit('message', this._parseConsumedMessage(data))
      }, {
        noAck: true
      })
    })
  }
}

module.exports = FanoutConsumer