<commit_before>// Handles sending requests to the daemon
import logger from '../logger'
import Session, {CancelHandlerType} from './session'
import {initEngine, initEngineSaga} from './require'
import {RPCError, convertToError} from '../util/errors'
import {isMobile} from '../constants/platform'
import {localLog} from '../util/forward-logs'
import {printOutstandingRPCs, isTesting} from '../local-debug'
import {resetClient, createClient, rpcLog, createClientType} from './index.platform'
import {createBatchChangeWaiting} from '../actions/waiting-gen'
import engineSaga from './saga'
import {throttle} from 'lodash-es'
import {CustomResponseIncomingCallMapType, IncomingCallMapType} from '.'
import {SessionID, SessionIDKey, WaitingHandlerType, MethodKey} from './types'
import {TypedState, Dispatch} from '../util/container'

type WaitingKey = string | Array<string>

function capitalize(s: string) {
  return s.charAt(0).toUpperCase() + s.slice(1)
}

class Engine {
  // Bookkeep old sessions
  _deadSessionsMap: {[K in SessionIDKey]: true} = {}
  // Tracking outstanding sessions
  _sessionsMap: {[K in SessionIDKey]: Session} = {}
  // Helper we delegate actual calls to
  _rpcClient: createClientType
  // Set which actions we don't auto respond with so sagas can themselves
  _customResponseAction: {[K in MethodKey]: true} = {}
  // We generate sessionIDs monotonically
  _nextSessionID: number = 123
  // We call onDisconnect handlers only if we've actually disconnected (ie connected once)
  _hasConnected: boolean = isMobile // mobile is always connected
  // App tells us when the sagas are done loading so we can start emitting events
  _sagasAreReady: boolean = false

  static _dispatch: Dispatch

  // Temporary helper for incoming call maps
  static _getState: () => TypedState

  _queuedChanges: Array<{error: RPCError; increment: boolean; key: WaitingKey}> = []
  dispatchWaitingAction = (key: WaitingKey, waiting: boolean, error: RPCError) => {
    this._queuedChanges.push({error, increment: waiting, key})
    this._throttledDispatchWaitingAction()
  }

  _throttledDispatchWaitingAction = throttle(() => {
    const changes = this._queuedChanges
    this._queuedChanges = []
    Engine._dispatch(createBatchChangeWaiting({changes}))
  }, 500)

  // TODO deprecate
  deprecatedGetDispatch = () => {
    return Engine._dispatch
  }
  // TODO deprecate
  deprecatedGetGetState = () => {
    return Engine._getState
  }

  constructor(dispatch: Dispatch, getState: () => TypedState) {
    // setup some static vars
    Engine._dispatch = dispatch
    Engine._getState = getState
    this._rpcClient = createClient(
      payload => this._rpcIncoming(payload),
      () => this._onConnected(),
      () => this._onDisconnect()
    )
    this._setupIgnoredHandlers()
    this._setupDebugging()
  }

  _setupDebugging() {
    if (!__DEV__) {
      return
    }

    if (typeof window !== 'undefined') {
      logger.info('DEV MODE ENGINE AVAILABLE AS window.DEBUGengine')
      // @ts-ignore codemode issue
      window.DEBUGengine = this
    }

    // Print out any alive sessions periodically
    if (printOutstandingRPCs) {
      setInterval(() => {
        if (Object.keys(this._sessionsMap).filter(k => !this._sessionsMap[k].getDangling()).length) {<commit_msg>bring back queuing but without batch (#20103)<commit_after>// Handles sending requests to the daemon
import logger from '../logger'
import Session, {CancelHandlerType} from './session'
import {initEngine, initEngineSaga} from './require'
import {RPCError, convertToError} from '../util/errors'
import {isMobile} from '../constants/platform'
import {localLog} from '../util/forward-logs'
import {printOutstandingRPCs, isTesting} from '../local-debug'
import {resetClient, createClient, rpcLog, createClientType} from './index.platform'
import {createBatchChangeWaiting} from '../actions/waiting-gen'
import engineSaga from './saga'
import {throttle} from 'lodash-es'
import {CustomResponseIncomingCallMapType, IncomingCallMapType} from '.'
import {SessionID, SessionIDKey, WaitingHandlerType, MethodKey} from './types'
import {TypedActions, TypedState, Dispatch} from '../util/container'

type WaitingKey = string | Array<string>

function capitalize(s: string) {
  return s.charAt(0).toUpperCase() + s.slice(1)
}

class Engine {
  // Bookkeep old sessions
  _deadSessionsMap: {[K in SessionIDKey]: true} = {}
  // Tracking outstanding sessions
  _sessionsMap: {[K in SessionIDKey]: Session} = {}
  // Helper we delegate actual calls to
  _rpcClient: createClientType
  // Set which actions we don't auto respond with so sagas can themselves
  _customResponseAction: {[K in MethodKey]: true} = {}
  // We generate sessionIDs monotonically
  _nextSessionID: number = 123
  // We call onDisconnect handlers only if we've actually disconnected (ie connected once)
  _hasConnected: boolean = isMobile // mobile is always connected
  // App tells us when the sagas are done loading so we can start emitting events
  _sagasAreReady: boolean = false

  static _realDispatch: Dispatch

  static _dispatchTimer: undefined | NodeJS.Timeout = undefined
  static _dispatchDeque = () => {
    Engine._dispatchTimer && clearTimeout(Engine._dispatchTimer)
    Engine._dispatchTimer = undefined
    if (!Engine._dispatchQueue.length) return

    const toDispatch = Engine._dispatchQueue
    Engine._dispatchQueue = []
    toDispatch.forEach(d => Engine._realDispatch(d))
  }
  static _dispatchQueue: Array<TypedActions> = []

  // So we can dispatch actions
  static _dispatch: Dispatch = (a: TypedActions) => {
    Engine._dispatchQueue.push(a)

    if (!Engine._dispatchTimer) {
      Engine._dispatchTimer = setTimeout(Engine._dispatchDeque, 0)
    }
  }

  // Temporary helper for incoming call maps
  static _getState: () => TypedState

  _queuedChanges: Array<{error: RPCError; increment: boolean; key: WaitingKey}> = []
  dispatchWaitingAction = (key: WaitingKey, waiting: boolean, error: RPCError) => {
    this._queuedChanges.push({error, increment: waiting, key})
    this._throttledDispatchWaitingAction()
  }

  _throttledDispatchWaitingAction = throttle(() => {
    const changes = this._queuedChanges
    this._queuedChanges = []
    Engine._dispatch(createBatchChangeWaiting({changes}))
  }, 500)

  // TODO deprecate
  deprecatedGetDispatch = () => {
    return Engine._dispatch
  }
  // TODO deprecate
  deprecatedGetGetState = () => {
    return Engine._getState
  }

  constructor(dispatch: Dispatch, getState: () => TypedState) {
    // setup some static vars
    Engine._realDispatch = dispatch
    Engine._getState = getState
    this._rpcClient = createClient(
      payload => this._rpcIncoming(payload),
      () => this._onConnected(),
      () => this._onDisconnect()
    )
    this._setupIgnoredHandlers()
    this._setupDebugging()
  }

  _setupDebugging() {
    if (!__DEV__) {
      return
    }

    if (typeof window !== 'undefined') {
      logger.info('DEV MODE ENGINE AVAILABLE AS window.DEBUGengine')
      // @ts-ignore codemode issue
      window.DEBUGengine = this
    }

    // Print out any alive sessions periodically
    if (printOutstandingRPCs) {
      setInterval(() => {
        if (Object.keys(this._sessionsMap).filter(k => !this._sessionsMap[k].getDangling()).length) {
{'fraction_non_alphanumeric': 0.11486208316179498, 'fraction_numerical': 0.003019075065184575, 'mean_word_length': 3.947725729803123, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '215784', 'n_tokens_mistral': 2159, 'n_tokens_neox': 2093, 'n_words': 588}