Source: server.js

const Session = require('./session');
const Bandwidther = require('./bandwidther');
const Request = require('./request');
const EventEmitter = require('events');
const Response = require('./response');
const Pinger = require('./pinger');
const ContinuityPinger = require('./continuity-pinger');
const ServerNetwork = require('./server-network');
const MeasurementSet = require('./measurement-set');
const Loki = require('lokijs');

/**
 * Client Q4S classs.
 * @extends EventEmitter
 */
class ServerQ4S extends EventEmitter {
  /**
   * Constructor for the Client.
   * @param {Object} serverOptions - Options to the client
   */
  constructor(serverOptions) {
    super();

    this.serverOps = serverOptions;
    const db = new Loki();
    this.store = db.addCollection('session');

    this.networkHandler = new ServerNetwork(this.store);
    this.networkHandler.on('handshake-Req', (req, done) =>
      this.handshakeHandler(req, done));
    const funt = (record, req, done) => {
      this.tCPReqHandler(record, req, done);
    };
    this.networkHandler.on('TCP-Req', funt);
  }
  /**
   * Start listening
   */
  async listen() {
    await this.networkHandler.listen(this.serverOps.portHanshakeTCP,
        this.serverOps.portTCP,
        this.serverOps.portUDP);
  }
  /**
   * Handler for handshake
   * @argument {ReqQ4S} req
   * @argument {function} done
   */
  handshakeHandler(req, done) {
    Session.serverGenerate(req.body, this.serverOps)
        .then((ses) => {
          ses.quality.constrain(this.serverOps);
          const session = this.store.insert(ses);
          session.id = session.$loki;
          session.state = Session.HANDSHAKE;
          this.store.update(session);
          const headers = {
            'Content-Type': 'application/sdp',
            'Session-Id': session.id,
          };
          done(Response.genRes(200, headers, session.toSdp()));
        });
  }
  /**
   * Handler for TCP
   * @argument {ReqQ4S} req
   * @argument {Session} record
   * @argument {function} done
   */
  tCPReqHandler(req, record, done) {
    if (req.method === 'READY' && req.headers.Stage === '0') {
      const pinger = Pinger.genServer(record.id, this.networkHandler,
          record.measurement.negotiationPingUp, 255);
      pinger.measure()
          .then((measures) => {
            const set = new MeasurementSet();
            set.introduceClientMeasures(measures.remote);
            set.introduceServerMeasures(measures.local);
            this.emit('measure', set);
            if (record.quality.doesMetQuality(set)) {
              record.state = Session.STAGE_0;
              this.store.update(record);
            } else {
              done(Request.genReq('ALERT-Q4S', '', undefined, undefined));
            }
          });
      done(Response.genRes(200, undefined, undefined));
    } else if (record.state === Session.STAGE_0 &&
      req.method === 'READY' &&
      req.headers.Stage === '1') {
      const tool = Bandwidther.genServer(record.id, this.networkHandler,
          record.quality.bandwidthDown,
          record.measurement.negotiationBandwidth);
      tool.measure()
          .then((measures) => {
            const set = new MeasurementSet();
            set.introduceClientMeasures(measures.remote);
            set.introduceServerMeasures(measures.local);
            this.emit('measure', set);
            if (record.quality.doesMetQuality(set)) {
              record.state = Session.STAGE_1;
              this.store.update(record);
            } else {
              record.state = Session.HANDSHAKE;
              this.store.update(record);
              this.sendAlert(record.id);
            }
          }
          ).catch((e) => {
            this.emit('error',
                new Error('Error in bandwidth measurement restarting')
            );
            record.state = Session.HANDSHAKE;
            this.store.update(record);
          });
      done(Response.genRes(200, undefined, undefined));
    } else if (record.state === Session.STAGE_1 &&
      req.method === 'READY' &&
      req.headers.Stage === '2') {
      const ping = ContinuityPinger.genServer(record.id, this.networkHandler,
          record.measurement.continuityPingDown,
          record.measurement.windowSizeUp);
      ping.on('measure', (measure) => {
        const set = new MeasurementSet();
        set.introduceClientMeasures(measure.remote);
        set.introduceServerMeasures(measure.local);
        this.emit('measure', set);
        if (record.quality.doesMetQuality(set)) {
          this.sendRecovery(record.id);
        } else {
          this.sendAlert(record.id);
        }
      });
      ping.measure();
      done(Response.genRes(200, undefined, undefined));
    } else if (req.method === 'CANCEL') {
      this.networkHandler.sendTCP(record.id, Request.genReq('CANCEL'));
      record.socket.end();
      this.store.remove(record);
      // Release session and send cancel
    } else {
      this.emit('error', new Error('recieved a request out of scope'));
    }
  }
  /**
   * Send an alert for the session Id
   * @argument {Number} sessionId
   */
  sendAlert(sessionId) {
    const record = this.store.findOne({
      'id': sessionId,
    });
    const now = new Date();
    if (record.lastAlert && now > record.lastAlert + record.alertPause) {
      record.lastAlert = now;
      record.qosLevelUp++;
      record.qosLevelDown++;
      this.store.update(record);
      this.networkHandler.sendTCP(sessionId,
          Request.genReq('ALERT-Q4S', 'example.com', undefined, undefined));
    }
  }
  /**
   * Send an recovery for the session Id
   * @argument {Number} sessionId
   */
  sendRecovery(sessionId) {
    const record = this.store.findOne({
      'id': sessionId,
    });
    const now = new Date();
    if (record.lastRecovery &&
      now > record.lastRecovery + record.recoveryPause) {
      record.lastRecovery = now;
      if (record.qosLevelUp > 0) {
        record.qosLevelUp--;
      }
      if (record.qosLevelDown > 0) {
        record.qosLevelDown--;
      }
      this.store.update(record);
      this.networkHandler.sendTCP(sessionId,
          Request.genReq('RECOVERY-Q4S', 'example.com', undefined, undefined));
    }
  }
}

module.exports = ServerQ4S;