Home Manual Reference Source

src/recognizer/websocket/networkWSInterface.js

import { recognizerLogger as logger } from '../../configuration/LoggerConfig';
import * as RecognizerContext from '../../model/RecognizerContext';

function infinitePing(websocket) {
  const websocketRef = websocket;
  websocketRef.pingLostCount++;
  if (websocketRef.pingLostCount > websocketRef.maxPingLost) {
    websocket.close(1000, 'PING_LOST');
  } else if (websocketRef.readyState <= 1) {
    setTimeout(() => {
      if (websocketRef.readyState <= 1) {
        websocketRef.send(JSON.stringify({ type: 'ping' }));
        infinitePing(websocketRef);
      }
    }, websocketRef.pingDelay);
  }
}

/**
 * Attach all socket attributes helping managing server connexion
 * @param {WebSocket} websocket Current WebSocket
 * @param {RecognizerContext} recognizerContext
 */
function addWebsocketAttributes(websocket, recognizerContext) {
  const websocketConfiguration = recognizerContext.editor.configuration.recognitionParams.server.websocket;
  const socket = websocket;
  socket.start = new Date();
  socket.autoReconnect = websocketConfiguration.autoReconnect;
  socket.maxRetryCount = websocketConfiguration.maxRetryCount;
  socket.pingEnabled = websocketConfiguration.pingEnabled;
  socket.pingDelay = websocketConfiguration.pingDelay;
  socket.maxPingLost = websocketConfiguration.maxPingLostCount;
  socket.pingLostCount = 0;
  socket.recognizerContext = recognizerContext;
}

/**
 * @param {RecognizerContext} recognizerContext Recognizer context
 * @return {WebSocket} Opened WebSocket
 */
export function openWebSocket(recognizerContext) {
  let socket;
  try {
    // eslint-disable-next-line no-undef
    socket = new WebSocket(recognizerContext.url);
  } catch (error) {
    logger.error('Unable to open websocket, Check the host and your connectivity');
  }
  addWebsocketAttributes(socket, recognizerContext);
  if (socket.pingEnabled) {
    infinitePing(socket);
  }

  socket.onopen = (e) => {
    logger.trace('onOpen');
    recognizerContext.websocketCallback(e);
  };

  socket.onclose = (e) => {
    logger.trace('onClose', new Date() - socket.start);
    recognizerContext.websocketCallback(e);
  };

  socket.onerror = (e) => {
    logger.trace('onError');
    recognizerContext.websocketCallback(e);
  };

  socket.onmessage = (e) => {
    logger.trace('onMessage');
    socket.pingLostCount = 0;
    const parsedMessage = JSON.parse(e.data);
    if (parsedMessage.type !== 'pong') {
      const callBackParam = {
        type: e.type,
        data: JSON.parse(e.data)
      };
      recognizerContext.websocketCallback(callBackParam);
    }
  };

  return socket;
}

/**
 * Send data message
 * @param {RecognizerContext} recognizerContext Current recognizer context
 * @param {Object} message Data message
 */
export function send(recognizerContext, message) {
  const recognizerContextRef = recognizerContext;
  recognizerContextRef.idle = false;

  const websocket = recognizerContextRef.websocket;
  if (websocket.readyState <= 1) {
    websocket.send(JSON.stringify(message));
    logger.debug(`${message.type} message sent`, message);
  } else {
    throw RecognizerContext.LOST_CONNEXION_MESSAGE;
  }
}

/**
 * Close the websocket
 * @param {RecognizerContext} recognizerContext Current recognizer context
 * @param {Number} code Exit code
 * @param {String} reason Exit reason
 */
export function close(recognizerContext, code, reason) {
  const websocket = recognizerContext.websocket;
  if (websocket && websocket.readyState < 2) {
    websocket.close(code, reason);
  }
}