Example #1
0
 /**
  *  Process open event.
  *
  *  @method processOpen
  *  @memberof module:ari-client~Client~start
  *  @private
  */
 function processOpen () {
   processingError = false;
   // reset backoff handler when we successfully connect
   retry = backoff.create({
     delay: 100
   });
   self.emit('WebSocketConnected');
   // onced, will not be called when an automatic reconnect succeeds.
   resolve();
 }
Example #2
0
  return new Promise(function(resolve, reject) {

    // Rewrite resolve/reject functions so they can only be called once and
    // each disables the other when called.
    resolve = _.once((function (oldResolve) {
        return function () {
          oldResolve();
          reject = function () {};
        };
    })(resolve));

    reject = _.once((function (oldReject) {
        return function () {
          oldReject();
          resolve = function () {};
        };
    })(reject));

    var applications = (_.isArray(apps)) ? apps.join(',') : apps;
    var wsUrl = util.format(
      'ws://%s/ari/events?app=%s&api_key=%s:%s',
      self._connection.host,
      applications,
      self._connection.user,
      self._connection.pass
    );

    if (subscribeAll) {
        wsUrl += '&subscribeAll=true';
    }

    var retry = backoff.create({
      delay: 100
    });

    connect();

    /**
     *  Connects to the application via WebSocket.
     *
     *  @method connect
     *  @memberof module:ari-client~Client~start
     *  @private
     */
    function connect () {
      self._ws = new WebSocket(wsUrl);

      self._ws.on('open', function () {
        processOpen();
      });
      self._ws.on('error', processError);
      self._ws.on('message', processMessage);
      self._ws.on('close', processClose);
    }

    /**
     *  Process message received by web socket and emit event.
     *
     *  @method processMessage
     *  @memberof module:ari-client~Client~start
     *  @private
     *  @param {Object} msg - the web socket message
     *  @param {Object} flags - web socket control flags
     */
    function processMessage (msg, flags) {
      var event = {};
      if (msg) {
        event = JSON.parse(msg);
      }
      var eventModels = self._swagger.apis.events.models;
      var eventModel = _.find(eventModels, function (item, key) {
        return key === event.type;
      });
      var resources = {};
      var instanceIds = [];

      // Pass in any property that is a known type as an object
      _.each(eventModel.properties, function (prop) {
        if (_.contains(_resources.knownTypes, prop.dataType) &&
            event[prop.name] !== undefined &&
            _resources[prop.dataType] !== undefined) {

          var instance = _resources[prop.dataType](
            self,
            event[prop.name]
          );
          resources[prop.name] = instance;

          // Keep track of which instance specific events we should
          // emit
          var listeners = self._instanceListeners[event.type];
          var instanceId = instance._id().toString();

          if (listeners) {
            var updatedListeners = [];

            _.each(listeners, function(listener) {
              if (listener.id === instanceId) {
                // make sure we do not duplicate events for a given instance
                if (!_.contains(instanceIds, instanceId)) {
                  instanceIds.push(instanceId);
                }

                // remove listeners that should only be invoked once
                if (!listener.once) {
                  updatedListeners.push(listener);
                }
              } else {
               updatedListeners.push(listener);
              }
            });

            self._instanceListeners[event.type] = updatedListeners;
          }
        }
      });

      var promoted = _.keys(resources).length;
      if (promoted === 1) {
        resources = resources[_.keys(resources)[0]];
      } else if (promoted === 0) {
        resources = undefined;
      }

      self.emit(event.type, event, resources);
      // If appropriate, emit instance specific events
      if (instanceIds.length > 0) {
        _.each(instanceIds, function (instanceId) {
          self.emit(
            util.format('%s-%s', event.type, instanceId),
            event,
            resources
          );
        });
      }
    }

    /**
     *  Process open event.
     *
     *  @method processOpen
     *  @memberof module:ari-client~Client~start
     *  @private
     */
    function processOpen () {
      processingError = false;
      // reset backoff handler when we successfully connect
      retry = backoff.create({
        delay: 100
      });
      self.emit('WebSocketConnected');
      // onced, will not be called when an automatic reconnect succeeds.
      resolve();
    }

    /**
     *  Process close event. Attempt to reconnect to web socket with a back off
     *  to ensure we do not flood the server.
     *
     *  @method processClose
     *  @memberof module:ari-client~Client~start
     *  @private
     *  @param {Number} reason - reason code for disconnect
     *  @param {String} description - reason text for disconnect
     */
    function processClose (reason, description) {
      // was connection closed on purpose?
      if (self._wsClosed) {
        self._wsClosed = false;

        return;
      }

      if (!processingError) {
        reconnect();
      }
    }

    /**
     *  Process error event.
     *
     *  @method processError
     *  @memberof module:ari-client~Client~start
     *  @private
     *  @param {Error} err - error object
     */
    function processError (err) {
      // was connection closed on purpose?
      if (self._wsClosed) {
        return;
      }

      processingError = true;

      reconnect(err);
    }

    /**
     *  Attempts to reconnect to the WebSocket using a backoff function.
     *
     *  @method reconnect
     *  @memberof module:ari-client~Client~start
     *  @private
     *  @param {Error} [err] - error object
     */
    function reconnect(err) {
      var scheduled = retry(connect);
      var msg = err ? err.message : 'unknown';

      if (!scheduled) {
        // onced or disabled if initial connection succeeds.
        reject(new Error('Connection attempts exceeded WebSocketMaxRetries. ' +
          msg));

        self.emit('WebSocketMaxRetries', err);
      } else {
        self.emit('WebSocketReconnecting', err);
      }
    }

  }).asCallback(callback);