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)

    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)
      }
    }
  } catch (error) {
    recognizerContext.recognitionContexts[0].initPromise.reject(error)
    logger.error('Unable to open websocket, Check the host and your connectivity')
  }

  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)
  }
}