<commit_before>// robot api client
// takes a dispatch (send) function and returns a receive handler
import {push} from 'react-router-redux'

import RpcClient from '../../../rpc/client'
import {actions, actionTypes} from '../actions'
import * as constants from '../constants'
import * as selectors from '../selectors'
import {handleDiscover} from './discovery'

// TODO(mc, 2017-11-01): get port from MDNS once API advertises proper port
const PORT = 31950
const RUN_TIME_TICK_INTERVAL_MS = 200
const NO_INTERVAL = -1
const RE_VOLUME = /.*?(\d+).*?/
const RE_TIPRACK = /tiprack/i
// TODO(mc, 2017-10-31): API supports mount, so this can be removed
const INSTRUMENT_AXES = {
  b: 'left',
  a: 'right'
}

export default function client (dispatch) {
  let rpcClient
  let remote

  // TODO(mc, 2017-09-22): build some sort of timer middleware instead?
  let runTimerInterval = NO_INTERVAL

  // return an action handler
  return function receive (state, action) {
    const {type} = action

    switch (type) {
      case actionTypes.DISCOVER: return handleDiscover(dispatch, state, action)
      case actionTypes.CONNECT: return connect(state, action)
      case actionTypes.DISCONNECT: return disconnect(state, action)
      case actionTypes.SESSION: return createSession(state, action)
      case actionTypes.PICKUP_AND_HOME: return pickupAndHome(state, action)
      case actionTypes.DROP_TIP_AND_HOME: return dropTipAndHome(state, action)
      case actionTypes.CONFIRM_TIPRACK: return confirmTiprack(state, action)
      case actionTypes.MOVE_TO_FRONT: return moveToFront(state, action)
      case actionTypes.PROBE_TIP: return probeTip(state, action)
      case actionTypes.MOVE_TO: return moveTo(state, action)
      case actionTypes.JOG: return jog(state, action)
      case actionTypes.UPDATE_OFFSET: return updateOffset(state, action)
      case actionTypes.RUN: return run(state, action)
      case actionTypes.PAUSE: return pause(state, action)
      case actionTypes.RESUME: return resume(state, action)
      case actionTypes.CANCEL: return cancel(state, action)
    }
  }

  function connect (state, action) {
    if (rpcClient) return dispatch(actions.connectResponse())

    RpcClient(`ws://${action.payload.host}:${PORT}`)
      .then((c) => {
        rpcClient = c
        rpcClient
          .on('notification', handleRobotNotification)
          .on('error', handleClientError)

        remote = rpcClient.remote

        if (remote.session_manager.session) {
          handleApiSession(remote.session_manager.session)
        }

        dispatch(actions.connectResponse())
      })
      .catch((e) => dispatch(actions.connectResponse(e)))
  }

  function disconnect () {
    if (!rpcClient) return dispatch(actions.disconnectResponse())

    rpcClient.close()
      .then(() => {
        // null out saved client and remote
        rpcClient = null
        remote = null

        clearRunTimerInterval()
        dispatch(actions.disconnectResponse())
        dispatch(push('/'))
      })
      .catch((error) => dispatch(actions.disconnectResponse(error)))
  }

  function createSession (state, action) {
    const file = action.payload.file
    const name = file.name
    const reader = new FileReader()

    reader.onload = function handleProtocolRead (event) {
      remote.session_manager.create(name, event.target.result)
        .then((apiSession) => {
          // TODO(mc, 2017-10-09): This seems like an API responsibility
          remote.session_manager.session = apiSession
          // TODO(mc, 2017-10-12) batch these updates and don't hardcode URL
          handleApiSession(apiSession, true)
        })
        .catch((error) => dispatch(actions.sessionResponse(error)))
    }

    dispatch(push('/upload'))
    return reader.readAsText(file)
  }

  function moveToFront (state, action) {
    const {payload: {instrument: axis}} = action
    const instrument = {_id: selectors.getInstrumentsByAxis(state)[axis]._id}

    // FIXME(mc, 2017-10-05): DEBUG CODE
    // return setTimeout(() => dispatch(actions.moveToFrontResponse()), 1000)

    remote.calibration_manager.move_to_front(instrument)
      .then(() => dispatch(actions.moveToFrontResponse()))
      .catch((error) => dispatch(actions.moveToFrontResponse(error)))
  }

  function pickupAndHome (state, action) {
    const {payload: {instrument: axis, labware: slot}} = action
    const instrument = {_id: selectors.getInstrumentsByAxis(state)[axis]._id}
    const labware = {_id: selectors.getLabwareBySlot(state)[slot]._id}

    remote.calibration_manager.pick_up_tip(instrument, labware)
      .then(() => remote.calibration_manager.home(instrument))
      .then(() => dispatch(actions.pickupAndHomeResponse()))
      .catch((error) => dispatch(actions.pickupAndHomeResponse(error)))
  }

  function dropTipAndHome (state, action) {
    const {payload: {instrument: axis, labware: slot}} = action
    const instrument = {_id: selectors.getInstrumentsByAxis(state)[axis]._id}
    const labware = {_id: selectors.getLabwareBySlot(state)[slot]._id}

    remote.calibration_manager.drop_tip(instrument, labware)<commit_msg>no need to home plunger after pick_up_tip()<commit_after>// robot api client
// takes a dispatch (send) function and returns a receive handler
import {push} from 'react-router-redux'

import RpcClient from '../../../rpc/client'
import {actions, actionTypes} from '../actions'
import * as constants from '../constants'
import * as selectors from '../selectors'
import {handleDiscover} from './discovery'

// TODO(mc, 2017-11-01): get port from MDNS once API advertises proper port
const PORT = 31950
const RUN_TIME_TICK_INTERVAL_MS = 200
const NO_INTERVAL = -1
const RE_VOLUME = /.*?(\d+).*?/
const RE_TIPRACK = /tiprack/i
// TODO(mc, 2017-10-31): API supports mount, so this can be removed
const INSTRUMENT_AXES = {
  b: 'left',
  a: 'right'
}

export default function client (dispatch) {
  let rpcClient
  let remote

  // TODO(mc, 2017-09-22): build some sort of timer middleware instead?
  let runTimerInterval = NO_INTERVAL

  // return an action handler
  return function receive (state, action) {
    const {type} = action

    switch (type) {
      case actionTypes.DISCOVER: return handleDiscover(dispatch, state, action)
      case actionTypes.CONNECT: return connect(state, action)
      case actionTypes.DISCONNECT: return disconnect(state, action)
      case actionTypes.SESSION: return createSession(state, action)
      case actionTypes.PICKUP_AND_HOME: return pickupAndHome(state, action)
      case actionTypes.DROP_TIP_AND_HOME: return dropTipAndHome(state, action)
      case actionTypes.CONFIRM_TIPRACK: return confirmTiprack(state, action)
      case actionTypes.MOVE_TO_FRONT: return moveToFront(state, action)
      case actionTypes.PROBE_TIP: return probeTip(state, action)
      case actionTypes.MOVE_TO: return moveTo(state, action)
      case actionTypes.JOG: return jog(state, action)
      case actionTypes.UPDATE_OFFSET: return updateOffset(state, action)
      case actionTypes.RUN: return run(state, action)
      case actionTypes.PAUSE: return pause(state, action)
      case actionTypes.RESUME: return resume(state, action)
      case actionTypes.CANCEL: return cancel(state, action)
    }
  }

  function connect (state, action) {
    if (rpcClient) return dispatch(actions.connectResponse())

    RpcClient(`ws://${action.payload.host}:${PORT}`)
      .then((c) => {
        rpcClient = c
        rpcClient
          .on('notification', handleRobotNotification)
          .on('error', handleClientError)

        remote = rpcClient.remote

        if (remote.session_manager.session) {
          handleApiSession(remote.session_manager.session)
        }

        dispatch(actions.connectResponse())
      })
      .catch((e) => dispatch(actions.connectResponse(e)))
  }

  function disconnect () {
    if (!rpcClient) return dispatch(actions.disconnectResponse())

    rpcClient.close()
      .then(() => {
        // null out saved client and remote
        rpcClient = null
        remote = null

        clearRunTimerInterval()
        dispatch(actions.disconnectResponse())
        dispatch(push('/'))
      })
      .catch((error) => dispatch(actions.disconnectResponse(error)))
  }

  function createSession (state, action) {
    const file = action.payload.file
    const name = file.name
    const reader = new FileReader()

    reader.onload = function handleProtocolRead (event) {
      remote.session_manager.create(name, event.target.result)
        .then((apiSession) => {
          // TODO(mc, 2017-10-09): This seems like an API responsibility
          remote.session_manager.session = apiSession
          // TODO(mc, 2017-10-12) batch these updates and don't hardcode URL
          handleApiSession(apiSession, true)
        })
        .catch((error) => dispatch(actions.sessionResponse(error)))
    }

    dispatch(push('/upload'))
    return reader.readAsText(file)
  }

  function moveToFront (state, action) {
    const {payload: {instrument: axis}} = action
    const instrument = {_id: selectors.getInstrumentsByAxis(state)[axis]._id}

    // FIXME(mc, 2017-10-05): DEBUG CODE
    // return setTimeout(() => dispatch(actions.moveToFrontResponse()), 1000)

    remote.calibration_manager.move_to_front(instrument)
      .then(() => dispatch(actions.moveToFrontResponse()))
      .catch((error) => dispatch(actions.moveToFrontResponse(error)))
  }

  function pickupAndHome (state, action) {
    const {payload: {instrument: axis, labware: slot}} = action
    const instrument = {_id: selectors.getInstrumentsByAxis(state)[axis]._id}
    const labware = {_id: selectors.getLabwareBySlot(state)[slot]._id}

    remote.calibration_manager.pick_up_tip(instrument, labware)
      .then(() => dispatch(actions.pickupAndHomeResponse()))
      .catch((error) => dispatch(actions.pickupAndHomeResponse(error)))
  }

  function dropTipAndHome (state, action) {
    const {payload: {instrument: axis, labware: slot}} = action
    const instrument = {_id: selectors.getInstrumentsByAxis(state)[axis]._id}
    const labware = {_id: selectors.getLabwareBySlot(state)[slot]._id}

    remote.calibration_manager.drop_tip(instrument, labware)
{'fraction_non_alphanumeric': 0.11753749632388981, 'fraction_numerical': 0.011959611802764435, 'mean_word_length': 3.5564984368021437, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 26, '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': '6064391', 'n_tokens_mistral': 3116, 'n_tokens_neox': 2955, 'n_words': 739}