model/RecognizerContext.js

import { recognizerLogger as logger } from '../configuration/LoggerConfig'

/**
 * Recognition context
 * @typedef {Object} RecognitionContext
 * @property {Model} model
 * @property {Callback} callback
 */

/**
 * Recognizer context
 * @typedef {Object} RecognizerContext
 * @property {Editor} editor Get a reference to the current editor
 * @property {Array<RecognitionContext>} recognitionContexts=[]
 * @property {Promise} initPromise=undefined
 * @property {RecognitionPositions} lastPositions  Last recognition sent/received stroke indexes.
 * @property {String} url=undefined
 * @property {WebSocket} websocket=undefined
 * @property {function} websocketCallback=undefined
 * @property {function} reconnect=undefined
 * @property {Number} currentReconnectionCount=0
 * @property {String} sessionId=undefined
 * @property {Number} contentPartCount=0
 * @property {String} currentPartId=undefined
 * @property {String} instanceId=undefined
 * @property {Boolean} canUndo=false
 * @property {Boolean} canRedo=false
 * @property {Boolean} isEmpty=false
 * @property {Array} supportedImportMimeTypes=[]
 * @property {Number} undoStackIndex=0
 * @property {Number} possibleUndoCount=0
 * @property {Boolean} idle=true
 * @property {Boolean} initialized=false
 */
/**
 * Create a new recognizer context
 * @param {Editor} editor
 * @return {RecognizerContext} An object that contains all recognizer context
 */
export function createEmptyRecognizerContext (editor) {
  const id = Date.now()
  logger.info('Create empty recognizer context with ID: ' + id)
  return {
    id,
    editor,
    // websocket
    recognitionContexts: [],
    initPromise: undefined,
    lastPositions: {
      lastSentPosition: -1,
      lastReceivedPosition: -1
    },
    url: undefined,
    websocket: undefined,
    websocketCallback: undefined,
    reconnect: undefined,
    currentReconnectionCount: 0,
    sessionId: undefined,
    contentPartCount: 0,
    currentPartId: undefined,
    instanceId: undefined,
    canUndo: false,
    canRedo: false,
    isEmpty: undefined,
    supportedImportMimeTypes: [],
    undoStackIndex: 0,
    possibleUndoCount: 0,
    idle: true,
    initialized: false
  }
}

/**
 * Return true if a reset is required, false otherwise
 * @param {RecognizerContext} recognizerContext
 * @param {Model} model
 * @return {Boolean}
 */
export function isResetRequired (recognizerContext, model) {
  if (recognizerContext.lastPositions) {
    return recognizerContext.lastPositions.lastSentPosition >= model.rawStrokes.length - 1
  }
  return false
}

/**
 * Update the recognition context positions
 * @param {RecognizerContext} recognizerContext Current recognizer context
 * @param {RecognitionPositions} positions Current recognition positions
 * @return {RecognizerContext}
 */
export function updateRecognitionPositions (recognizerContext, positions) {
  const recognizerContextRef = recognizerContext
  if (positions) {
    recognizerContextRef.lastPositions.lastSentPosition = positions.lastSentPosition
    recognizerContextRef.lastPositions.lastReceivedPosition = positions.lastReceivedPosition
  }
  if (recognizerContextRef.lastPositions.lastSentPosition === recognizerContextRef.lastPositions.lastReceivedPosition === -1) {
    delete recognizerContextRef.instanceId
  }
  return recognizerContextRef
}

/**
 * Set the recognition context
 * @param {RecognizerContext} recognizerContext Current recognizer context
 * @param {RecognitionContext} recognitionContext
 * @return {RecognizerContext}
 */
export function setRecognitionContext (recognizerContext, recognitionContext) {
  const recognizerContextRef = recognizerContext
  recognizerContextRef.recognitionContexts[0] = recognitionContext
  return recognizerContextRef
}

/**
 * Test if it is possible to reconnect
 * @param {RecognizerContext} recognizerContext
 * @return {Boolean} True if possible, false otherwise
 */
export function canReconnect (recognizerContext) {
  return recognizerContext.websocket && recognizerContext.websocket.autoReconnect === true &&
    recognizerContext.currentReconnectionCount <= recognizerContext.websocket.maxRetryCount &&
    (!recognizerContext.error || !['api.invalid.format', 'access.not.granted'].includes(recognizerContext.error.code))
}

/**
 * Test if it should attempt immediate reconnect
 * @param {RecognizerContext} recognizerContext
 * @return {Boolean} True if should attempt reconnect, false otherwise
 */
export function shouldAttemptImmediateReconnect (recognizerContext) {
  recognizerContext.currentReconnectionCount++
  return canReconnect(recognizerContext)
}

/**
 * Lost connection message
 * @type {{type: string}}
 */
export const LOST_CONNEXION_MESSAGE = { type: 'LOST_CONNECTION' }

/**
 * Explicit close message
 * @type {String}
 */
export const CLOSE_RECOGNIZER_MESSAGE = 'CLOSE_RECOGNIZER'