baja/comm/BoxFrame.js

/**
 * @copyright 2015 Tridium, Inc. All Rights Reserved.
 * @author Gareth Johnson
 */

/**
 * Defines {@link baja.comm.BoxFrame}.
 * @module baja/comm/BoxFrame
 * @private
 */
define([ "bajaScript/sys" ], function (baja) {
  "use strict";
    
  /*
  // A BOX frame
  var boxFrame = {
    "p": "box", // Protocol
    "d": "stationName" // Destination (if blank, null or undefined, it's for the locally connected host/station)
    "v": "2",    // Version
    "n": 1,      // Unique frame id number
    "m": [ {     // A frame contains an array of messages
        // The body of each message (response must have some order and number for each message)
        {
          "r": 0,      // Response id (used to associate requests with responses). Used when HTTP isn't. -1 === unsolicited.
          "t": "rt",   // Type (rt=request, rp=response, e=response error, u=unsolicited, )
          "c": "sys",      // Channel (pluggable comms model)
          "k": "getTypes", // Key in Channel
          "b": {           // Message body
          }  
        }
      }
    ]
  };
  */
  
  /**
   * A BOX frame to be stringified and sent up to the station.
   * 
   * There are some advanced properties that can be added to a BoxFrame
   * instance. This helps the comms layer to decide how to deal with the
   * message. The '$sync' property can be set to `true` to send the message
   * synchronously, or to `'beacon'` to send the message as a beacon. The
   * '$queue' boolean property is used to determine whether the frame should be
   * queued against other queued frames. Both are advanced options should only
   * ever be used by Tridium developers.
   *
   * @class
   * @alias baja.comm.BoxFrame
   * @private
   * @param {Array} messageQueue A queue of BOX messages.
   * 
   * @example
   *   //JSON representation of a BOX frame.
   *   
   *   var boxFrameJson = {
   *     "p": "box", // Protocol
   *     "d": "stationName" // Destination (if blank, null or undefined, it's for the locally connected host/station)
   *     "v": 2,     // Version
   *     "n": 3,     // Unique frame id number
   *     "m": [ {    // A frame contains an array of messages
   *       // The body of each message (response must have some order and number for each message)
   *       {
   *         "r": 0,      // Response id (used to associate requests with responses). Used when HTTP isn't. -1 === unsolicited.
   *         "t": "rt",   // Type (rt=request, rp=response, e=response error, u=unsolicited, )
   *         "c": "sys",      // Channel (pluggable comms model)
   *         "k": "getTypes", // Key in Channel
   *         "b": {           // Message body
   *         }  
   *       }
   *     } ]
   * };
   * 
   */
  var BoxFrame = function BoxFrame(messageQueue) {
    var msgs = [],
        i;
    
    for (i = 0; i < messageQueue.length; ++i) {
      if (messageQueue[i].m) {
        msgs.push(messageQueue[i].m);
      }
    }
        
    this.$body = {
      p: 'box',  // protocol
      v: '2.3',    // version
      m: msgs,   // messages (actual messages from a MessageQueue - no callbacks)
      id: baja.comm.getServerSessionId(),
      n: baja.comm.incrementFrameId() // frame sequence number
    };
  };
  
  /**
   * Returns a JSON-stringified representation of this BOX frame, ready to be
   * sent up to the station as-is.
   *
   * @returns {String} a string representation of this BOX frame in a format
   * expected by the BOX servlet on the station.
   */
  BoxFrame.prototype.toString = function () {
    return JSON.stringify(this.$body);
  };
  
  /**
   * Checks to see if this frame has no actual messages to send.
   *
   * @returns {Boolean} true if this frame has no messages.
   */
  BoxFrame.prototype.isEmpty = function () {
    return this.$body.m.length === 0;
  };
  
  /**
   * Sends this frame up to the station. This is an override hook and MUST be
   * implemented by a utility class; e.g. `browser.js` will
   * implement this by using `XMLHttpRequest` to send this frame to the station
   * via POST. This function will be called from 
   * {@link baja.comm.Batch#commit} so any batch properties on the
   * callback object do not need to be taken into account - just ok/fail.
   * 
   * @abstract
   * @param {baja.comm.Batch|baja.comm.Callback|Object} callback an object
   * containing ok/fail callbacks.
   */
  BoxFrame.prototype.send = function (callback) {
    throw new Error("baja.comm.BoxFrame#send not implemented");
  };
  
  /**
   * Return the sequence number for the BOX frame.
   * 
   * Every new BOX Frame has a unique sequence number associated with it.
   *
   * @returns {Number}
   */
  BoxFrame.prototype.getSequenceNum = function () {
    return this.$body.n;
  };
  
  return BoxFrame;
});