Cleanup error classes

This commit is contained in:
Chris Clark
2015-10-27 17:14:23 -07:00
parent 37178eeb0b
commit 87dac75919
5 changed files with 53 additions and 175 deletions

View File

@@ -4,7 +4,7 @@ const WebSocket = require('ws');
// temporary: RangeSet will be moved to api/common soon // temporary: RangeSet will be moved to api/common soon
const RangeSet = require('./rangeset').RangeSet; const RangeSet = require('./rangeset').RangeSet;
const {RippledError, DisconnectedError, NotConnectedError, const {RippledError, DisconnectedError, NotConnectedError,
TimeoutError, UnexpectedError} = require('./errors'); TimeoutError, ResponseFormatError} = require('./errors');
function isStreamMessageType(type) { function isStreamMessageType(type) {
return type === 'ledgerClosed' || return type === 'ledgerClosed' ||
@@ -29,7 +29,7 @@ class Connection extends EventEmitter {
const data = JSON.parse(message); const data = JSON.parse(message);
if (data.type === 'response') { if (data.type === 'response') {
if (!(Number.isInteger(data.id) && data.id >= 0)) { if (!(Number.isInteger(data.id) && data.id >= 0)) {
throw new UnexpectedError('valid id not found in response'); throw new ResponseFormatError('valid id not found in response');
} }
return [data.id.toString(), data]; return [data.id.toString(), data];
} else if (isStreamMessageType(data.type)) { } else if (isStreamMessageType(data.type)) {
@@ -43,7 +43,7 @@ class Connection extends EventEmitter {
} else if (data.type === undefined && data.error) { } else if (data.type === undefined && data.error) {
return ['error', data.error, data.error_message]; // e.g. slowDown return ['error', data.error, data.error_message]; // e.g. slowDown
} }
throw new UnexpectedError('unrecognized message type: ' + data.type); throw new ResponseFormatError('unrecognized message type: ' + data.type);
} }
_onMessage(message) { _onMessage(message) {
@@ -207,7 +207,7 @@ class Connection extends EventEmitter {
} else if (response.status === 'success') { } else if (response.status === 'success') {
_resolve(response.result); _resolve(response.result);
} else { } else {
_reject(new UnexpectedError( _reject(new ResponseFormatError(
'unrecognized status: ' + response.status)); 'unrecognized status: ' + response.status));
} }
}); });

View File

@@ -1,169 +1,77 @@
/* eslint-disable valid-jsdoc */
'use strict'; 'use strict';
const util = require('util'); const util = require('util');
const utils = require('./utils');
/** class RippleError extends Error {
* Base class for all errors constructor(message) {
*/ super(message);
function RippleError(message) { this.name = this.constructor.name;
this.message = message; this.message = message;
} Error.captureStackTrace(this, this.constructor.name);
}
RippleError.prototype = Object.create(Error.prototype); toString() {
RippleError.prototype.name = 'RippleError';
RippleError.prototype.toString = function() {
let result = '[' + this.name + '(' + this.message; let result = '[' + this.name + '(' + this.message;
if (this.data) { if (this.data) {
result += ', ' + util.inspect(this.data); result += ', ' + util.inspect(this.data);
} }
result += ')]'; result += ')]';
return result; return result;
}; }
/* /* console.log in node uses util.inspect on object, and util.inspect allows
console.log in node uses util.inspect on object, and util.inspect allows us to cutomize its output:
to cutomize it output: https://nodejs.org/api/util.html#util_custom_inspect_function_on_objects */
https://nodejs.org/api/util.html#util_custom_inspect_function_on_objects inspect() {
*/
RippleError.prototype.inspect = function(depth) {
utils.unused(depth);
return this.toString(); return this.toString();
};
class RippledError extends RippleError {
constructor(message) {
super(message);
this.name = this.constructor.name;
this.message = message;
Error.captureStackTrace(this, this.constructor.name);
} }
} }
class ConnectionError extends RippleError { class RippledError extends RippleError {}
class UnexpectedError extends RippleError {}
class ConnectionError extends RippleError {}
class NotConnectedError extends ConnectionError {}
class DisconnectedError extends ConnectionError {}
class TimeoutError extends ConnectionError {}
class ResponseFormatError extends ConnectionError {}
class ValidationError extends RippleError {}
class NotFoundError extends RippleError {
constructor(message) { constructor(message) {
super(message); super(message || 'Not found');
this.name = this.constructor.name;
this.message = message;
Error.captureStackTrace(this, this.constructor.name);
} }
} }
class NotConnectedError extends ConnectionError { class MissingLedgerHistoryError extends RippleError {
constructor(message) { constructor(message) {
super(message); super(message || 'Server is missing ledger history in the specified range');
} }
} }
class DisconnectedError extends ConnectionError { class PendingLedgerVersionError extends RippleError {
constructor(message) { constructor(message) {
super(message); super(message || 'maxLedgerVersion is greater than server\'s'
+ 'most recent validated ledger');
} }
} }
class TimeoutError extends ConnectionError {
constructor(message) {
super(message);
}
}
class UnexpectedError extends ConnectionError {
constructor(message) {
super(message);
}
}
function ValidationError(message) {
this.message = message;
}
ValidationError.prototype = new RippleError();
ValidationError.prototype.name = 'ValidationError';
/**
* Timeout, disconnects and too busy
*/
function NetworkError(message) {
this.message = message;
}
NetworkError.prototype = new RippleError();
NetworkError.prototype.name = 'NetworkError';
/**
* Failed transactions, no paths found, not enough balance, etc.
*/
function RippledNetworkError(message) {
this.message = message !== undefined ? message : 'Cannot connect to rippled';
}
RippledNetworkError.prototype = new NetworkError();
/**
* Failed transactions, no paths found, not enough balance, etc.
*/
function TransactionError(message) {
this.message = message;
}
TransactionError.prototype = new RippleError();
TransactionError.prototype.name = 'TransactionError';
/**
* Asset could not be found
*/
function NotFoundError(message) {
this.message = message;
}
NotFoundError.prototype = new RippleError();
NotFoundError.prototype.name = 'NotFoundError';
function MissingLedgerHistoryError(message) {
this.message = message ||
'Server is missing ledger history in the specified range';
}
MissingLedgerHistoryError.prototype = new RippleError();
MissingLedgerHistoryError.prototype.name = 'MissingLedgerHistoryError';
function PendingLedgerVersionError(message) {
this.message = message ||
'maxLedgerVersion is greater than server\'s most recent validated ledger';
}
PendingLedgerVersionError.prototype = new RippleError();
PendingLedgerVersionError.prototype.name = 'PendingLedgerVersionError';
/**
* Request timed out
*/
function TimeOutError(message) {
this.message = message;
}
TimeOutError.prototype = new RippleError();
TimeOutError.prototype.name = 'TimeOutError';
/**
* API logic failed to do what it intended
*/
function ApiError(message) {
this.message = message;
}
ApiError.prototype = new RippleError();
ApiError.prototype.name = 'ApiError';
module.exports = { module.exports = {
ValidationError,
NetworkError,
TransactionError,
RippledNetworkError,
NotFoundError,
PendingLedgerVersionError,
MissingLedgerHistoryError,
TimeOutError,
ApiError,
RippleError, RippleError,
UnexpectedError,
ConnectionError, ConnectionError,
RippledError, RippledError,
NotConnectedError, NotConnectedError,
DisconnectedError, DisconnectedError,
TimeoutError, TimeoutError,
UnexpectedError ResponseFormatError,
ValidationError,
NotFoundError,
PendingLedgerVersionError,
MissingLedgerHistoryError
}; };

View File

@@ -38,7 +38,7 @@ function generateAddressAPI(options?: Object): Object {
try { try {
return generateAddress(options); return generateAddress(options);
} catch (error) { } catch (error) {
throw new errors.ApiError(error.message); throw new errors.UnexpectedError(error.message);
} }
} }

View File

@@ -28,9 +28,9 @@ function attachTransactionDate(connection: Connection, tx: Object
if (typeof data.ledger.close_time === 'number') { if (typeof data.ledger.close_time === 'number') {
return _.assign({date: data.ledger.close_time}, tx); return _.assign({date: data.ledger.close_time}, tx);
} }
throw new errors.ApiError('Ledger missing close_time'); throw new errors.UnexpectedError('Ledger missing close_time');
}).catch(error => { }).catch(error => {
if (error instanceof errors.ApiError) { if (error instanceof errors.UnexpectedError) {
throw error; throw error;
} }
throw new errors.NotFoundError('Transaction ledger not found'); throw new errors.NotFoundError('Transaction ledger not found');

View File

@@ -419,9 +419,9 @@ describe('RippleAPI', function() {
const hash = const hash =
'0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A04'; '0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A04';
return this.api.getTransaction(hash).then(() => { return this.api.getTransaction(hash).then(() => {
assert(false, 'Should throw ApiError'); assert(false, 'Should throw UnexpectedError');
}).catch(error => { }).catch(error => {
assert(error instanceof this.api.errors.ApiError); assert(error instanceof this.api.errors.UnexpectedError);
}); });
}); });
}); });
@@ -854,36 +854,6 @@ describe('RippleAPI', function() {
}); });
describe('common errors', function() {
it('TransactionError', function() {
// TransactionError is not used anywhere, so just test its creation
assert.throws(function() {
throw new common.errors.TransactionError('fall through');
}, this.api.errors.TransactionError);
assert.throws(function() {
throw new common.errors.TransactionError('fall through');
}, /fall through/);
});
it('TimeOutError', function() {
// TimeOutError is not used anywhere, so just test its creation
assert.throws(function() {
throw new common.errors.TimeOutError('fall through');
}, this.api.errors.TimeOutError);
assert.throws(function() {
throw new common.errors.TimeOutError('fall through');
}, /fall through/);
});
it('RippledNetworkError', function() {
assert.throws(function() {
throw new common.errors.RippledNetworkError();
}, /Cannot connect to rippled/);
});
});
it('ledgerClosed', function(done) { it('ledgerClosed', function(done) {
this.api.on('ledgerClosed', message => { this.api.on('ledgerClosed', message => {
checkResult(responses.ledgerClosed, 'ledgerClosed', message); checkResult(responses.ledgerClosed, 'ledgerClosed', message);