Browse Source

De/serialize process related errors so they get correctly reported to sentry

also should now have the stack
master
Gaëtan Renaudeau 7 years ago
parent
commit
62f4f47599
  1. 2
      src/api/Ethereum.js
  2. 2
      src/api/Fees.js
  3. 2
      src/api/network.js
  4. 2
      src/commands/libcoreGetFees.js
  5. 2
      src/commands/libcoreHardReset.js
  6. 2
      src/components/EnsureDeviceApp/index.js
  7. 2
      src/components/RequestAmount/index.js
  8. 2
      src/components/modals/Send/index.js
  9. 2
      src/helpers/apps/installApp.js
  10. 2
      src/helpers/apps/uninstallApp.js
  11. 14
      src/helpers/createCustomErrorClass.js
  12. 2
      src/helpers/devices/getNextMCU.js
  13. 79
      src/helpers/errors.js
  14. 2
      src/helpers/getAddressForCurrency/btc.js
  15. 7
      src/helpers/ipc.js
  16. 2
      src/helpers/libcore.js
  17. 2
      src/helpers/socket.js
  18. 7
      src/internals/index.js

2
src/api/Ethereum.js

@ -1,6 +1,6 @@
// @flow
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
import network from './network'
import { blockchainBaseURL } from './Ledger'

2
src/api/Fees.js

@ -2,7 +2,7 @@
import invariant from 'invariant'
import LRU from 'lru-cache'
import type { Currency } from '@ledgerhq/live-common/lib/types'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
import { blockchainBaseURL } from './Ledger'
import network from './network'

2
src/api/network.js

@ -3,7 +3,7 @@ import axios from 'axios'
import { GET_CALLS_RETRY, GET_CALLS_TIMEOUT } from 'config/constants'
import { retry } from 'helpers/promise'
import logger from 'logger'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
export const LedgerAPIErrorWithMessage = createCustomErrorClass('LedgerAPIErrorWithMessage')
export const LedgerAPIError = createCustomErrorClass('LedgerAPIError')

2
src/commands/libcoreGetFees.js

@ -5,7 +5,7 @@ import withLibcore from 'helpers/withLibcore'
import { createCommand, Command } from 'helpers/ipc'
import * as accountIdHelper from 'helpers/accountId'
import { isValidAddress } from 'helpers/libcore'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
const InvalidAddress = createCustomErrorClass('InvalidAddress')

2
src/commands/libcoreHardReset.js

@ -3,7 +3,7 @@
import { createCommand } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import withLibcore from 'helpers/withLibcore'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
const HardResetFail = createCustomErrorClass('HardResetFail')

2
src/components/EnsureDeviceApp/index.js

@ -13,7 +13,7 @@ import type { State as StoreState } from 'reducers/index'
import getAddress from 'commands/getAddress'
import { standardDerivation } from 'helpers/derivations'
import isDashboardOpen from 'commands/isDashboardOpen'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
import { CHECK_APP_INTERVAL_WHEN_VALID, CHECK_APP_INTERVAL_WHEN_INVALID } from 'config/constants'

2
src/components/RequestAmount/index.js

@ -21,7 +21,7 @@ import InputCurrency from 'components/base/InputCurrency'
import Button from 'components/base/Button'
import Box from 'components/base/Box'
import type { State } from 'reducers'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')

2
src/components/modals/Send/index.js

@ -15,7 +15,7 @@ import { getBridgeForCurrency } from 'bridge'
import { accountsSelector } from 'reducers/accounts'
import { updateAccountWithUpdater } from 'actions/accounts'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
import { MODAL_SEND } from 'config/constants'
import Modal, { ModalBody, ModalContent, ModalTitle } from 'components/base/Modal'

2
src/helpers/apps/installApp.js

@ -7,7 +7,7 @@ import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/common'
import createCustomErrorClass from '../createCustomErrorClass'
import { createCustomErrorClass } from '../errors'
const ManagerUnexpectedError = createCustomErrorClass('ManagerUnexpected')
const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace')

2
src/helpers/apps/uninstallApp.js

@ -6,7 +6,7 @@ import { BASE_SOCKET_URL_SECURE } from 'config/constants'
import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/common'
import createCustomErrorClass from '../createCustomErrorClass'
import { createCustomErrorClass } from '../errors'
const ManagerUnexpectedError = createCustomErrorClass('ManagerUnexpectedError')
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked')

14
src/helpers/createCustomErrorClass.js

@ -1,14 +0,0 @@
// @flow
export default (name: string): Class<any> => {
const C = function CustomError(message?: string, fields?: Object) {
this.name = name
this.message = message || name
this.stack = new Error().stack
Object.assign(this, fields)
}
// $FlowFixMe
C.prototype = new Error()
// $FlowFixMe we can't easily type a subset of Error for now...
return C
}

2
src/helpers/devices/getNextMCU.js

@ -2,7 +2,7 @@
import network from 'api/network'
import { GET_NEXT_MCU } from 'helpers/urls'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { createCustomErrorClass } from 'helpers/errors'
const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError')

79
src/helpers/errors.js

@ -1,3 +1,80 @@
// @flow
/* eslint-disable no-continue */
export const formatError = (e: Error) => e.message
const errorClasses = {}
export const createCustomErrorClass = (name: string): Class<any> => {
const C = function CustomError(message?: string, fields?: Object) {
this.name = name
this.message = message || name
this.stack = new Error().stack
Object.assign(this, fields)
}
// $FlowFixMe
C.prototype = new Error()
errorClasses[name] = C
// $FlowFixMe we can't easily type a subset of Error for now...
return C
}
// inspired from https://github.com/programble/errio/blob/master/index.js
export const deserializeError = (object: mixed): Error => {
if (typeof object === 'object' && object) {
const constructor = (typeof object.name === 'string' && errorClasses[object.name]) || Error
const error = Object.create(constructor.prototype)
for (const prop in object) {
if (object.hasOwnProperty(prop)) {
error[prop] = object[prop]
}
}
if (!error.stack && Error.captureStackTrace) {
Error.captureStackTrace(error, deserializeError)
}
return error
}
return new Error(String(object))
}
// inspired from https://github.com/sindresorhus/serialize-error/blob/master/index.js
export const serializeError = (value: mixed) => {
if (!value) return value
if (typeof value === 'object') {
return destroyCircular(value, [])
}
if (typeof value === 'function') {
return `[Function: ${value.name || 'anonymous'}]`
}
return value
}
// https://www.npmjs.com/package/destroy-circular
function destroyCircular(from: Object, seen) {
const to = {}
seen.push(from)
for (const key of Object.keys(from)) {
const value = from[key]
if (typeof value === 'function') {
continue
}
if (!value || typeof value !== 'object') {
to[key] = value
continue
}
if (seen.indexOf(from[key]) === -1) {
to[key] = destroyCircular(from[key], seen.slice(0))
continue
}
to[key] = '[Circular]'
}
if (typeof from.name === 'string') {
to.name = from.name
}
if (typeof from.message === 'string') {
to.message = from.message
}
if (typeof from.stack === 'string') {
to.stack = from.stack
}
return to
}

2
src/helpers/getAddressForCurrency/btc.js

@ -4,7 +4,7 @@ import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import Btc from '@ledgerhq/hw-app-btc'
import type Transport from '@ledgerhq/hw-transport'
import getBitcoinLikeInfo from '../devices/getBitcoinLikeInfo'
import createCustomErrorClass from '../createCustomErrorClass'
import { createCustomErrorClass } from '../errors'
const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp')

7
src/helpers/ipc.js

@ -2,6 +2,7 @@
import logger from 'logger'
import { Observable } from 'rxjs'
import uuidv4 from 'uuid/v4'
import { deserializeError } from './errors'
export function createCommand<In, A>(id: string, impl: In => Observable<A>): Command<In, A> {
return new Command(id, impl)
@ -60,10 +61,12 @@ function ipcRendererSendCommand<In, A>(id: string, data: In): Observable<A> {
ipcRenderer.removeListener('command-event', handleCommandEvent)
break
case 'cmd.ERROR':
o.error(msg.data)
case 'cmd.ERROR': {
const error = deserializeError(msg.data)
o.error(error)
ipcRenderer.removeListener('command-event', handleCommandEvent)
break
}
default:
}

2
src/helpers/libcore.js

@ -11,7 +11,7 @@ import type { NJSAccount, NJSOperation } from '@ledgerhq/ledger-core/src/ledgerc
import { isSegwitAccount } from 'helpers/bip32'
import * as accountIdHelper from 'helpers/accountId'
import createCustomErrorClass from './createCustomErrorClass'
import { createCustomErrorClass } from './errors'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName'

2
src/helpers/socket.js

@ -5,7 +5,7 @@ import logger from 'logger'
import Websocket from 'ws'
import type Transport from '@ledgerhq/hw-transport'
import { Observable } from 'rxjs'
import createCustomErrorClass from './createCustomErrorClass'
import { createCustomErrorClass } from './errors'
const WebsocketConnectionError = createCustomErrorClass('WebsocketConnectionError')
const WebsocketConnectionFailed = createCustomErrorClass('WebsocketConnectionFailed')

7
src/internals/index.js

@ -5,6 +5,7 @@ import uuid from 'uuid/v4'
import { setImplementation } from 'api/network'
import sentry from 'sentry/node'
import { DEBUG_NETWORK } from 'config/constants'
import { serializeError } from 'helpers/errors'
require('../env')
@ -75,11 +76,7 @@ process.on('message', m => {
process.send({
type: 'cmd.ERROR',
requestId,
data: {
...error,
name: error && error.name,
message: error && error.message,
},
data: serializeError(error),
})
},
})

Loading…
Cancel
Save