ripple/ripple-rest

View on GitHub
server/error-handler.js

Summary

Maintainability
C
1 day
Test Coverage
'use strict';
var config = require('./config');
var respond = require('./response-handler.js');
var errors = require('./api').errors;
var logger = require('./logger.js').logger;

var InvalidRequestError = errors.InvalidRequestError;
var NetworkError = errors.NetworkError;
var RippledNetworkError = errors.RippledNetworkError;
var NotFoundError = errors.NotFoundError;
var TimeOutError = errors.TimeOutError;
var ApiError = errors.ApiError;
var DatabaseError = errors.DatabaseError;
var RippleError = errors.RippleError;
var RippleLibError = require('ripple-lib').RippleError;


function isRippleError(error) {
  return error instanceof RippleError || error instanceof RippleLibError;
}

function handleError(error, req, res, next) {
  // If in debug mode, print errors
  if (config.get('debug')) {
    if (error && error.remote) {
      logger.error(error.remote);
    } else if (error && error.stack) {
      logger.error(error.stack);
    } else {
      logger.error(error);
    }
  } else if (error.stack && !isRippleError(error)) {
    // always log stack traces for uncaught exceptions
    logger.error(error.stack);
  }

  var err_obj = {
    success: false,
    error: (error.remote ? error.remote.error : null)
      || error.engine_result || error.error || error.message || error,
    message: (error.remote ? error.remote.error_message : null)
      || error.engine_result_message || error.error_message || error.message
      || error
  };

  if (err_obj.error === 'txnNotFound' || err_obj.error === 'actNotFound') {
    respond.transactionNotFoundError(res, undefined, err_obj);
    next();
    return;
  }

  /* Handle ripple-lib errors */
  if (err_obj.error === 'remoteError') {
    if (err_obj.message === 'Account not found.') {
      err_obj.error = 'Invalid address or secret.';
      err_obj.message = 'Please ensure the address and secret correspond to a '
        + 'valid account that has a positive XRP balance.';

    } else {
      err_obj.error = 'Internal Error';
      err_obj.message = 'ripple-lib reported an error. If the problem '
        + 'persists, please try restarting the server. Error: '
        + JSON.stringify(err_obj.message);
    }
  }

  if (err_obj.error === 'Cannot generate keys from invalid seed!'
      || err_obj.error === 'temBAD_AUTH_MASTER') {
    err_obj.error = 'Invalid address or secret.';
    err_obj.message = 'Please ensure the address and secret correspond to a '
      + 'valid account that has a positive XRP balance.';
  }

  if (err_obj.error === 'tooBusy') {
    err_obj.error = 'Rippled Busy';
    err_obj.message = 'The server is experiencing heavy load and is unable '
      + 'to process the request right now. Please try again.';
  }

  /* Add info to rippled error messages */
  if (err_obj.error === 'tecPATH_DRY') {
    err_obj.message = err_obj.message + ' Please ensure that the '
      + 'source_address has sufficient funds (in the source_amount currency, '
      + 'if specified) to execute this transaction.';
  }

  if (err_obj.error === 'telINSUF_FEE_P') {
    err_obj.message = err_obj.message + ' Please ensure that the '
      + 'source_address has sufficient XRP to pay the fee. If it does, please '
      + 'report this error, this service should handle setting the proper fee.';
  }

  if (err_obj.error === 'tecPATH_PARTIAL') {
    err_obj.message = err_obj.message + ' Please try getting payment options '
      + 'first to ensure that there is a way to execute this payment. If you '
      + 'submitted a payment from the list of options, the path may have '
      + 'changed already, please try getting payment options again and '
      + 'submitting one of those or setting the "source_slippage" higher.';
  }

  if (err_obj.error === err_obj.message) {
    var err_array = err_obj.error.split('. ');
    err_obj.error = err_array[0];
    err_obj.message = err_array.slice(1).join('. ');
  }

  if (!err_obj.message) {
    delete err_obj.message;
  }

  switch (error.name) {
    case InvalidRequestError.name:
      respond.invalidRequest(res, error);
      break;
    case NetworkError.name:
      respond.connectionError(res, undefined, err_obj);
      break;
    case RippledNetworkError.name:
      respond.connectionError(res, undefined, err_obj);
      break;
    case NotFoundError.name:
      respond.notFoundError(res, error);
      break;
    case TimeOutError.name:
      respond.timeOutError(res, undefined, err_obj);
      break;
    case ApiError.name:
      respond.apiError(res, error);
      break;
    case DatabaseError.name:
      respond.apiError(res, undefined, err_obj);
      break;
    default:
      respond.transactionError(res, undefined, err_obj);
      break;
  }
  next();
}

module.exports = handleError;