<commit_before>import asap from 'asap'
import cookies from 'js-cookie'
import fpSortBy from 'lodash/fp/sortBy'
import React from 'react'
import updater from 'xoa-updater'
import URL from 'url-parse'
import Xo from 'xo-lib'
import { createBackoff } from 'jsonrpc-websocket-client'
import { get as getDefined } from '@xen-orchestra/defined'
import { pFinally, reflect, tap, tapCatch } from 'promise-toolbox'
import { SelectHost } from 'select-objects'
import { filter, forEach, get, includes, isEmpty, isEqual, map, once, size, sortBy, throttle } from 'lodash'
import { forbiddenOperation, noHostsAvailable, vmIsTemplate } from 'xo-common/api-errors'

import _ from '../intl'
import fetch, { post } from '../fetch'
import invoke from '../invoke'
import Icon from '../icon'
import logError from '../log-error'
import renderXoItem, { renderXoItemFromId } from '../render-xo-item'
import store from 'store'
import { alert, chooseAction, confirm } from '../modal'
import { error, info, success } from '../notification'
import { getObject } from 'selectors'
import { noop, resolveId, resolveIds } from '../utils'
import {
  connected,
  disconnected,
  markObjectsFetched,
  signedIn,
  signedOut,
  updateObjects,
  updatePermissions,
} from '../store/actions'

import parseNdJson from './_parseNdJson'

// ===================================================================

export const ITEMS_PER_PAGE_OPTIONS = [10, 20, 50, 100]

// ===================================================================

export const XEN_DEFAULT_CPU_WEIGHT = 256
export const XEN_DEFAULT_CPU_CAP = 0

// ===================================================================

export const XEN_VIDEORAM_VALUES = [1, 2, 4, 8, 16]

// ===================================================================

export const isSrWritable = sr => sr && sr.content_type !== 'iso' && sr.size > 0
export const isSrShared = sr => sr && sr.shared
export const isVmRunning = vm => vm && vm.power_state === 'Running'

// ===================================================================

export const signOut = () => {
  // prevent automatic reconnection
  xo.removeListener('closed', connect)

  cookies.remove('token')
  window.location.reload(true)
}

export const connect = () => {
  xo.open(createBackoff()).catch(error => {
    logError(error, 'failed to connect to xo-server')
  })
}

const xo = invoke(() => {
  const token = cookies.get('token')
  if (!token) {
    signOut()
    throw new Error('no valid token')
  }

  const xo = new Xo({
    credentials: { token },
  })

  xo.on('authenticationFailure', signOut)
  xo.on('scheduledAttempt', ({ delay }) => {
    console.warn('next attempt in %s ms', delay)
  })

  xo.on('closed', connect)

  return xo
})
connect()

const _signIn = new Promise(resolve => xo.once('authenticated', resolve))

const _call = new URLSearchParams(window.location.search.slice(1)).has('debug')
  ? async (method, params) => {
      await _signIn
      // eslint-disable-next-line no-console
      console.debug('API call', method, params)
      return tap.call(xo.call(method, params), null, error => {
        console.error('XO error', {
          method,
          params,
          code: error.code,
          message: error.message,
          data: error.data,
        })
      })
    }
  : (method, params) => _signIn.then(() => xo.call(method, params))

// ===================================================================

export const connectStore = store => {
  let updates = {}
  const sendUpdates = throttle(() => {
    store.dispatch(updateObjects(updates))
    updates = {}<commit_msg>feat(xo-web/debug): display API call result<commit_after>import asap from 'asap'
import cookies from 'js-cookie'
import fpSortBy from 'lodash/fp/sortBy'
import React from 'react'
import updater from 'xoa-updater'
import URL from 'url-parse'
import Xo from 'xo-lib'
import { createBackoff } from 'jsonrpc-websocket-client'
import { get as getDefined } from '@xen-orchestra/defined'
import { pFinally, reflect, tap, tapCatch } from 'promise-toolbox'
import { SelectHost } from 'select-objects'
import { filter, forEach, get, includes, isEmpty, isEqual, map, once, size, sortBy, throttle } from 'lodash'
import { forbiddenOperation, noHostsAvailable, vmIsTemplate } from 'xo-common/api-errors'

import _ from '../intl'
import fetch, { post } from '../fetch'
import invoke from '../invoke'
import Icon from '../icon'
import logError from '../log-error'
import renderXoItem, { renderXoItemFromId } from '../render-xo-item'
import store from 'store'
import { alert, chooseAction, confirm } from '../modal'
import { error, info, success } from '../notification'
import { getObject } from 'selectors'
import { noop, resolveId, resolveIds } from '../utils'
import {
  connected,
  disconnected,
  markObjectsFetched,
  signedIn,
  signedOut,
  updateObjects,
  updatePermissions,
} from '../store/actions'

import parseNdJson from './_parseNdJson'

// ===================================================================

export const ITEMS_PER_PAGE_OPTIONS = [10, 20, 50, 100]

// ===================================================================

export const XEN_DEFAULT_CPU_WEIGHT = 256
export const XEN_DEFAULT_CPU_CAP = 0

// ===================================================================

export const XEN_VIDEORAM_VALUES = [1, 2, 4, 8, 16]

// ===================================================================

export const isSrWritable = sr => sr && sr.content_type !== 'iso' && sr.size > 0
export const isSrShared = sr => sr && sr.shared
export const isVmRunning = vm => vm && vm.power_state === 'Running'

// ===================================================================

export const signOut = () => {
  // prevent automatic reconnection
  xo.removeListener('closed', connect)

  cookies.remove('token')
  window.location.reload(true)
}

export const connect = () => {
  xo.open(createBackoff()).catch(error => {
    logError(error, 'failed to connect to xo-server')
  })
}

const xo = invoke(() => {
  const token = cookies.get('token')
  if (!token) {
    signOut()
    throw new Error('no valid token')
  }

  const xo = new Xo({
    credentials: { token },
  })

  xo.on('authenticationFailure', signOut)
  xo.on('scheduledAttempt', ({ delay }) => {
    console.warn('next attempt in %s ms', delay)
  })

  xo.on('closed', connect)

  return xo
})
connect()

const _signIn = new Promise(resolve => xo.once('authenticated', resolve))

const _call = new URLSearchParams(window.location.search.slice(1)).has('debug')
  ? async (method, params) => {
      await _signIn
      return tap.call(
        xo.call(method, params),
        result => {
          // eslint-disable-next-line no-console
          console.debug('API call', method, params, result)
        },
        error => {
          console.error('XO error', {
            method,
            params,
            code: error.code,
            message: error.message,
            data: error.data,
          })
        }
      )
    }
  : (method, params) => _signIn.then(() => xo.call(method, params))

// ===================================================================

export const connectStore = store => {
  let updates = {}
  const sendUpdates = throttle(() => {
    store.dispatch(updateObjects(updates))
    updates = {}
{'fraction_non_alphanumeric': 0.23642085100560953, 'fraction_numerical': 0.005746340128608565, 'mean_word_length': 3.9291975724882, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 36, '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': '5922045', 'n_tokens_mistral': 2230, 'n_tokens_neox': 2109, 'n_words': 578}