Source: session.js

/**
 * Session manipulation class. Implements  methods to build sessions from sdp
 * and to generate new sdp.
 * @module Session
 */

const DefaultProcedure = require('./default-procedure');
const Addresses = require('./addresses');
const MeasurementSet = require('./measurement-set');
const util = require('./util');


/** Session class. Options to build , generate and parse sessions*/
class Session {
  /**
   * Constructor for the ReqQ4S class. Does not validate input data coherence.
   * @param {number} qosLevelUp - Contains the QoS level for uplink. May be
   * changed during session
   * @param {number} qosLevelDown - Contains the QoS level for downlink. May
   * be changed during session
   * @param {number} alertingMode - The configured alert mode setted up for
   * this session.
   * @param {number} alertPause - Alert pause value, number of miliseconds
   * between Alert q4s messages.
   * @param {Number} recoveryPause - Number of miliseconds to wait.
   * @param {Number} state - The State of the current session
   * @param {Number} id - The session Id of this session.
   * @param {Addresses} addresses - The IP version of the client
   * address.
   * @param {MeasurementSet} quality - The client IP address.
   * @param {DefaultProcedure} measurement - The client IP address.
   */
  constructor(qosLevelUp, qosLevelDown, alertingMode, alertPause,
      recoveryPause, state, id, addresses, quality,
      measurement) {
    this.qosLevelUp = qosLevelUp;
    this.qosLevelDown = qosLevelDown;
    this.alertingMode = alertingMode;
    this.alertPause = alertPause;
    this.recoveryPause = recoveryPause;
    this.state = state;
    if (addresses) {
      this.addresses = addresses;
    } else {
      this.addresses = new Addresses();
    }
    if (quality) {
      this.quality = quality;
    } else {
      this.quality = new MeasurementSet();
    }
    if (measurement) {
      this.measurement = measurement;
    } else {
      this.measurement = new DefaultProcedure();
    }
    this.id = id;
  }
  /**
   * Factory static method to generate a new session from an SDP.
   * @param {string} sdp - The sdp message to generate a new session.
   */
  updateWithSDP(sdp) {
    const lines = sdp.split('\r\n');
    lines.forEach((line) => {
      if (line.indexOf('a=') === 0) {
        if (line.indexOf('a=qos-level:') === 0) {
          const aux = line.substring(12).split('/');
          this.qosLevelUp = parseInt(aux[0], 10);
          this.qosLevelDown = parseInt(aux[1], 10);
        } else if (line.indexOf('a=alerting-mode:') === 0) {
          const aux = line.substring(16);
          if (aux.localeCompare('Q4S-aware-network') === 0) {
            this.alertingMode = ALERT_TYP.Q4SAWARE;
          }
        } else if (line.indexOf('a=alert-pause:') === 0) {
          this.alertPause = parseInt(line.substring(14), 10);
        } else if (line.indexOf('a=recovery-pause:') === 0) {
          this.recoveryPause = parseInt(line.substring(14), 10);
        } else if (line.indexOf('a=public-address') === 0) {
          this.addresses.updateFromSDP(line);
        } else if (line.indexOf('a=measurement:procedure') === 0) {
          this.measurement = new DefaultProcedure();
          this.measurement.updateFromAttr(line.substring(24));
        } else if (line.indexOf('a=latency:') === 0) {
          this.quality.updateWithSDP(line);
        } else if (line.indexOf('a=jitter:') === 0) {
          this.quality.updateWithSDP(line);
        } else if (line.indexOf('a=bandwidth:') === 0) {
          this.quality.updateWithSDP(line);
        } else if (line.indexOf('a=packetloss:') === 0) {
          this.quality.updateWithSDP(line);
        } else if (line.indexOf('a=flow') === 0) {
          this.addresses.updateFromSDP(line);
        }
      } else if (line.indexOf('o=') === 0) {
        this.id = line.split(' ')[1];
      }
    });
  }

  /**
   * Returns a promise with the sdp representation of this session
   * @return {string} -  Sdp format of this session.
   */
  toSdp() {
    let sdp = 'o=q4s ' + this.id + ' 2353687637 IN IPx xxx.xxx.xxx.xxx\r\n';
    sdp = sdp + 'a=qos-level:' + this.qosLevelUp + '/' +
      this.qosLevelDown + '\r\n';
    if (this.alertingMode === REACTIVE) {
      sdp = sdp + 'a=alerting-mode:Reactive\r\n';
    } else {
      sdp = sdp + 'a=alerting-mode:Q4S-aware-network\r\n';
    }
    sdp = sdp + 'a=alert-pause:' + this.alertPause + '\r\n';
    sdp = sdp + this.addresses.ipToSdp();
    sdp = sdp + 'a=measurement:procedure ' + this.measurement.toAttr() +
      '\r\n';
    sdp = sdp + this.quality.toSDPAttr();
    sdp = sdp + this.addresses.portToSDP();
    return sdp;
  }

  /**
   * Creates a session from the options passed-
   * @argument {Object} options - Options
   * @return {Session} -  A new session
   */
  static async fromClientOps(options) {
    const qosLevelUp = 0;
    const qosLevelDown = 0;
    const alertingMode = REACTIVE;
    const alertPause = 1000;
    const recoveryPause = 1000;
    let latency = 0;
    let jitterUp = 0;
    let jitterDown = 0;
    let bandwidthUp = 0;
    let bandwidthDown = 0;
    let packetlossUp = 0;
    let packetlossDown = 0;
    const q4sClientPorts = {};
    const appClientPorts = {};

    if (options.latency) {
      latency = options.latency;
    }
    if (options.jitterUp) {
      jitterUp = options.jitterUp;
    }
    if (options.jitterDown) {
      jitterDown = options.jitterDown;
    }
    if (options.bandwidthUp) {
      bandwidthUp = options.bandwidthUp;
    }
    if (options.bandwidthDown) {
      bandwidthDown = options.bandwidthDown;
    }
    if (options.packetlossUp) {
      packetlossUp = options.packetlossUp;
    }
    if (options.packetlossDown) {
      packetlossDown = options.packetlossDown;
    }
    const quality = new MeasurementSet(latency, jitterUp, jitterDown,
        bandwidthUp, bandwidthDown, packetlossUp, packetlossDown);
    if (options.portTCP) {
      q4sClientPorts.TCP = options.portTCP;
    }
    if (options.portUDP) {
      q4sClientPorts.UDP = options.portUDP;
    }
    if (options.appPortsTCP) {
      appClientPorts.TCP = options.appPortsTCP;
    }
    if (options.appPortsUDP) {
      appClientPorts.UDP = options.appPortsUDP;
    }
    let host;
    if (options.ip) {
      if (options.ip === 'private') {
        host = util.getPrivateIp();
      } else if (options.ip === 'public') {
        host = await util.getPublicIp();
      } else {
        host = options.ip;
      }
    } else {
      host = await util.getPublicIp();
    }
    const addresses = new Addresses(4, host,
        undefined, undefined, q4sClientPorts, undefined, appClientPorts,
        undefined);

    const measurement = new DefaultProcedure();
    return new Session(qosLevelUp, qosLevelDown, alertingMode, alertPause,
        recoveryPause, UNINITIATED, undefined, addresses, quality, measurement);
  }

  /**
   * Generates a session with an sdp and serveroptions.
   * @argument {String} sdp
   * @argument {Object} serverOps
   * @return {Session} -  A new session
   */
  static async serverGenerate(sdp, serverOps) {
    const ses = new Session();
    ses.updateWithSDP(sdp);
    ses.measurement.fromOptions(serverOps.procedure);
    ses.qosLevelUp = 0;
    ses.qosLevelDown = 0;
    ses.alertingMode = serverOps.alertingMode;
    ses.alertPause = serverOps.alertPause;
    ses.recoveryPause = serverOps.recoveryPause;
    ses.state = UNINITIATED;
    let host;
    if (serverOps.ip) {
      if (serverOps.ip === 'private') {
        host = util.getPrivateIp();
      } else if (serverOps.ip === 'public') {
        host = await util.getPublicIp();
      } else {
        host = serverOps.ip;
      }
    } else {
      host = await util.getPublicIp();
    }
    ses.addresses.serverAddressType = 4;
    ses.addresses.serverAddress = host;
    ses.addresses.q4sServerPorts.TCP = serverOps.portTCP;
    ses.addresses.q4sServerPorts.UDP = serverOps.portUDP;
    ses.addresses.appServerPorts.TCP = serverOps.appPortsTCP;
    ses.addresses.appServerPorts.UDP = serverOps.appPortsUDP;
    return ses;
  }
}

const Q4SAWARE = 0;
const REACTIVE = 1;
const STAGE_0 = 0;
const STAGE_1 = 1;
const CONTINUITY = 2;
const HANDSHAKE = 3;
const TERMINATION = 4;
const UNINITIATED = 5;


/**
 * A constant object that exports the two alerting modes that can be possible
 * in a session
 */
module.exports = Session;
module.exports.Q4SAWARE = Q4SAWARE;
module.exports.REACTIVE = REACTIVE;
module.exports.STAGE_0 = STAGE_0;
module.exports.STAGE_1 = STAGE_1;
module.exports.CONTINUITY = CONTINUITY;
module.exports.HANDSHAKE = HANDSHAKE;
module.exports.TERMINATION = TERMINATION;
module.exports.UNINITIATED = UNINITIATED;