Source: source/WebSocketJson.js

export default WebSocketJson;

/**
  * @constructor
  * @description
  * Data source which connects to a websocket server, parses a JSON object out of websocket frames, and calls data
  * handlers with the parsed object. This source can also respond to each frame received with a static value, allowing
  * servers to rate limit data based on how quickly the client can respond.
  *
  * Each WebSocketJson instance creates its own websocket connection.
  *
  * @param {WebSocketJson.Options} userOptions User provided options
  */
function WebSocketJson(options) {

  /**
    * @typedef WebSocketJson.Options
    *
    * @description
    * These are the options specific to this class.
    *
    * @property {String} type     Data source type. Must be "WebSocketJson",
    * @property {String} url      Websocket server url. (e.g. "ws://localhost:8001")
    * @property {String} ackFrame Optional value to send as an acknowledgement to the websocket server after each frame
    *                             is received. If this option is undefined, no acknowledgement will be sent.
    **/
  console.assert(options.type === "WebSocketJson");
  this._conn = new WebSocket(options.url);
  this._conn.binaryType = "arraybuffer";
  this._conn.onopen = this._onopen.bind(this);
  this._conn.onclose = this._onclose.bind(this);
  this._conn.onmessage = this._onmessage.bind(this);
  this._handlers = [];
  this._ackFrame = options.ackFrame;
}

WebSocketJson.prototype = {

  /**
   * Adds a handler function to be called when a websocket frame is received by this data source.
   *
   * @param {Function} handler function called with the websocket frame object as the single argument.
   */
  addHandler(handler) {
    /* Only add unique handlers */
    if (this._handlers.indexOf(handler) === -1) {
      this._handlers.push(handler);
    }
  },

  /**
   * Removes a registered handler function if it exists in this data source
   *
   * @param {Function} handler function to be removed
   */
  removeHandler(handler) {
    let index = this._handlers.indexOf(handler);
    if (index !== -1) {
      this._handlers.splice(index, 1);
    }
  },

  /**
   * @private
   * @description Handler for websocket onopen event
   */
  _onopen : function() {
    if (typeof this._ackFrame !== "undefined") {
      this._conn.send(this._ackFrame);
    }
  },

  /**
   * @private
   * @description Handler for websocket onmessage event
   */
  _onmessage : function(msg) {
    let json = JSON.parse(msg.data);

    for (let i = 0; i < this._handlers.length; i++) {
      this._handlers[i](json);
    }

    if (typeof this._ackFrame !== "undefined") {
      this._conn.send(this._ackFrame);
    }
  },

  /**
   * @private
   * @description Handler for websocket onclose event
   */
  _onclose : function() {
    /* pass */
  }
}