Source: utils/eventUtils.js

/**
 * @file Manages helper functions to work with events
 * @author Ivan Violentov <ivan.violentov@jibrel.network>
 */

import Promise from 'bluebird'
import EventEmitter from 'events'

import config from '../config'

/**
 * @callback eventCallback
 *
 * @param {Object} error
 * @param {Object} event
 */

/**
 * @function subscribe
 *
 * @description Subscribes to provided event
 *
 * @param {function} Event - Function for event subscribing
 * @param {object} [options={}] - Event options
 * @param {object} [options.filter] - Filter options by indexed event parameters
 * @param {(number|string)} [options.fromBlock] - The number of the earliest block
 * @param {(number|string)} [options.toBlock] - The number of the latest block
 * @param {(string|string[])} [options.address] - An address(es) to get logs from
 * @param {string[]} [options.topics] - Allows to manually set the topics for the event filter
 * @param {eventCallback} [callback] - Callback which fired for each event or error
 *
 * @returns {object} The event emitter has the following events:<br />
 * - data: Fires on each incoming event with the event object as argument<br />
 * - error: Fires when an error in the subscription occours
 */
export function subscribe(Event, options = {}, callback) {
  const eventEmitter = new EventEmitter()

  /**
   * web3@0.x.x event takes filter and additional options in different params
   * web3@1.x.x event takes all options in one param
   */
  const { filter, ...additionalOptions } = options

  Event(filter, additionalOptions, (err, result) => {
    if (err) {
      /**
       * Error event
       *
       * @event subscribeErrorEvent
       * @type {object}
       */
      eventEmitter.emit('error', err)

      if (callback) {
        callback(err)
      }

      return
    }

    /**
     * Data event
     *
     * @event subscribeDataEvent
     * @type {object}
     */
    eventEmitter.emit('data', result)

    if (callback) {
      callback(null, result)
    }
  })

  return eventEmitter
}

/**
 * @async
 * @function getEvents
 *
 * @description Gets past events
 *
 * @param {function} Event - Function to get past events
 * @param {object} [options={}] - Event options
 * @param {object} [options.filter] - Filter options by indexed event parameters
 * @param {(number|string)} [options.fromBlock] - The number of the earliest block
 * @param {(number|string)} [options.toBlock] - The number of the latest block
 * @param {(string|string[])} [options.address] - An address(es) to get logs from
 * @param {string[]} [options.topics] - Allows to manually set the topics for the event filter
 *
 * @returns Promise that will be resolved with past events
 */
export function getEvents(Event, options = {}) {
  /**
   * web3@0.x.x event takes filter and additional options in different params
   * web3@1.x.x event takes all options in one param
   */
  const { filter, ...additionalOptions } = options
  const event = Event(filter, additionalOptions)

  /**
   * event.get uses instance methods inside,
   * but bluebird promisify don't save context,
   * so need to bind to event object directly
   */
  return Promise
    .promisify(event.get.bind(event))()
    .timeout(
      config.promiseTimeout,
      new Error(`Can not get past events within ${config.promiseTimeout}ms`)
    )
}