mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-23 05:35:48 +00:00
Merge notifications functionality into getAccountTransactions
This commit is contained in:
@@ -6,7 +6,6 @@ const balances = require('./ledger/balances');
|
|||||||
const settings = require('./ledger/settings');
|
const settings = require('./ledger/settings');
|
||||||
const transactions = require('./ledger/transactions');
|
const transactions = require('./ledger/transactions');
|
||||||
const trustlines = require('./ledger/trustlines');
|
const trustlines = require('./ledger/trustlines');
|
||||||
const notifications = require('./ledger/notifications');
|
|
||||||
const payments = require('./ledger/payments');
|
const payments = require('./ledger/payments');
|
||||||
const orders = require('./ledger/orders');
|
const orders = require('./ledger/orders');
|
||||||
const preparePayment = require('./transaction/payment');
|
const preparePayment = require('./transaction/payment');
|
||||||
@@ -41,8 +40,6 @@ RippleAPI.prototype = {
|
|||||||
getSettings: settings.getSettings,
|
getSettings: settings.getSettings,
|
||||||
getTransaction: transactions.getTransaction,
|
getTransaction: transactions.getTransaction,
|
||||||
getAccountTransactions: transactions.getAccountTransactions,
|
getAccountTransactions: transactions.getAccountTransactions,
|
||||||
getNotification: notifications.getNotification,
|
|
||||||
getNotifications: notifications.getNotifications,
|
|
||||||
|
|
||||||
preparePayment: preparePayment,
|
preparePayment: preparePayment,
|
||||||
prepareTrustline: prepareTrustline,
|
prepareTrustline: prepareTrustline,
|
||||||
|
|||||||
40
src/api/common/schemas/acct-tx-options.json
Normal file
40
src/api/common/schemas/acct-tx-options.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "acct-tx-options",
|
||||||
|
"description": "Options for getAccountTransactions",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"start": {"$ref": "hash256"},
|
||||||
|
"limit": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"minLedgerVersion": {"$ref": "ledgerVersion"},
|
||||||
|
"maxLedgerVersion": {"$ref": "ledgerVersion"},
|
||||||
|
"earliestFirst": {"type": "boolean"},
|
||||||
|
"excludeFailures": {"type": "boolean"},
|
||||||
|
"outgoing": {"type": "boolean"},
|
||||||
|
"incoming": {"type": "boolean"},
|
||||||
|
"types": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"enum": [
|
||||||
|
"payment",
|
||||||
|
"trustline",
|
||||||
|
"order",
|
||||||
|
"orderCancellation",
|
||||||
|
"settings"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"binary": {"type": "boolean"}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"not": {
|
||||||
|
"anyOf": [
|
||||||
|
{"required": ["incoming", "outgoing"]},
|
||||||
|
{"required": ["start", "minLedgerVersion"]},
|
||||||
|
{"required": ["start", "maxLedgerVersion"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,8 +33,8 @@ function validateLedgerRange(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateOptions(options) {
|
function validateOptions(schema, options) {
|
||||||
schemaValidate('options', options);
|
schemaValidate(schema, options);
|
||||||
validateLedgerRange(options);
|
validateLedgerRange(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ module.exports = {
|
|||||||
trustline: _.partial(schemaValidate, 'trustline'),
|
trustline: _.partial(schemaValidate, 'trustline'),
|
||||||
txJSON: _.partial(schemaValidate, 'tx'),
|
txJSON: _.partial(schemaValidate, 'tx'),
|
||||||
blob: _.partial(schemaValidate, 'blob'),
|
blob: _.partial(schemaValidate, 'blob'),
|
||||||
options: validateOptions,
|
getAccountTransactionsOptions: _.partial(validateOptions, 'acct-tx-options'),
|
||||||
|
options: _.partial(validateOptions, 'options'),
|
||||||
instructions: _.partial(schemaValidate, 'instructions')
|
instructions: _.partial(schemaValidate, 'instructions')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,329 +0,0 @@
|
|||||||
/* eslint-disable valid-jsdoc */
|
|
||||||
'use strict';
|
|
||||||
const _ = require('lodash');
|
|
||||||
const async = require('async');
|
|
||||||
const transactions = require('./transactions');
|
|
||||||
const NotificationParser = require('./parse/notification');
|
|
||||||
const utils = require('./utils');
|
|
||||||
const validate = utils.common.validate;
|
|
||||||
const server = utils.common.server;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the previous and next transaction hashes.
|
|
||||||
* Report errors to the client using res.json
|
|
||||||
* or pass the notificationDetails with the added fields
|
|
||||||
* back to the callback.
|
|
||||||
*
|
|
||||||
* @param {Remote} $.remote
|
|
||||||
* @param {Express.js Response} res
|
|
||||||
* @param {RippleAddress} notificationDetails.account
|
|
||||||
* @param {Ripple Transaction in JSON Format} notificationDetails.transaction
|
|
||||||
* @param {Hex-encoded String} notificationDetails.identifier
|
|
||||||
* @param {Function} callback
|
|
||||||
*
|
|
||||||
* @callback
|
|
||||||
* @param {Error} error
|
|
||||||
* @param {Object} notificationDetails
|
|
||||||
**/
|
|
||||||
|
|
||||||
function attachPreviousAndNextTransactionIdentifiers(api,
|
|
||||||
notificationDetails, topCallback) {
|
|
||||||
|
|
||||||
// Get all of the transactions affecting the specified
|
|
||||||
// account in the given ledger. This is done so that
|
|
||||||
// we can query for one more than that number on either
|
|
||||||
// side to ensure that we'll find the next and previous
|
|
||||||
// transactions, no matter how many transactions the
|
|
||||||
// given account had in the same ledger
|
|
||||||
function getAccountTransactionsInBaseTransactionLedger(callback) {
|
|
||||||
const params = {
|
|
||||||
account: notificationDetails.account,
|
|
||||||
ledger_index_min: notificationDetails.transaction.ledger_index,
|
|
||||||
ledger_index_max: notificationDetails.transaction.ledger_index,
|
|
||||||
exclude_failed: false,
|
|
||||||
max: 99999999,
|
|
||||||
limit: 200 // arbitrary, just checking number of transactions in ledger
|
|
||||||
};
|
|
||||||
|
|
||||||
transactions.getAccountTransactions(api, params, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query for one more than the numTransactionsInLedger
|
|
||||||
// going forward and backwards to get a range of transactions
|
|
||||||
// that will definitely include the next and previous transactions
|
|
||||||
function getNextAndPreviousTransactions(txns, callback) {
|
|
||||||
const numTransactionsInLedger = txns.length;
|
|
||||||
async.concat([false, true], function(earliestFirst, concat_callback) {
|
|
||||||
const params = {
|
|
||||||
account: notificationDetails.account,
|
|
||||||
max: numTransactionsInLedger + 1,
|
|
||||||
min: numTransactionsInLedger + 1,
|
|
||||||
limit: numTransactionsInLedger + 1,
|
|
||||||
earliestFirst: earliestFirst
|
|
||||||
};
|
|
||||||
|
|
||||||
// In rippled -1 corresponds to the first or last ledger
|
|
||||||
// in its database, depending on whether it is the min or max value
|
|
||||||
if (params.earliestFirst) {
|
|
||||||
params.ledger_index_max = -1;
|
|
||||||
params.ledger_index_min = notificationDetails.transaction.ledger_index;
|
|
||||||
} else {
|
|
||||||
params.ledger_index_max = notificationDetails.transaction.ledger_index;
|
|
||||||
params.ledger_index_min = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions.getAccountTransactions(api, params, concat_callback);
|
|
||||||
|
|
||||||
}, callback);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort the transactions returned by ledger_index and remove duplicates
|
|
||||||
function sortTransactions(allTransactions, callback) {
|
|
||||||
allTransactions.push(notificationDetails.transaction);
|
|
||||||
|
|
||||||
const txns = _.uniq(allTransactions, function(tx) {
|
|
||||||
return tx.hash;
|
|
||||||
});
|
|
||||||
|
|
||||||
txns.sort(utils.compareTransactions);
|
|
||||||
|
|
||||||
callback(null, txns);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the baseTransaction amongst the results. Because the
|
|
||||||
// transactions have been sorted, the next and previous transactions
|
|
||||||
// will be the ones on either side of the base transaction
|
|
||||||
function findPreviousAndNextTransactions(txns, callback) {
|
|
||||||
|
|
||||||
// Find the index in the array of the baseTransaction
|
|
||||||
const baseTransactionIndex = _.findIndex(txns, function(possibility) {
|
|
||||||
return possibility.hash === notificationDetails.transaction.hash;
|
|
||||||
});
|
|
||||||
|
|
||||||
// The previous transaction is the one with an index in
|
|
||||||
// the array of baseTransactionIndex - 1
|
|
||||||
if (baseTransactionIndex > 0) {
|
|
||||||
const previous_transaction = txns[baseTransactionIndex - 1];
|
|
||||||
notificationDetails.previous_transaction_identifier =
|
|
||||||
previous_transaction.hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The next transaction is the one with an index in
|
|
||||||
// the array of baseTransactionIndex + 1
|
|
||||||
if (baseTransactionIndex + 1 < txns.length) {
|
|
||||||
const next_transaction = txns[baseTransactionIndex + 1];
|
|
||||||
notificationDetails.next_transaction_identifier = next_transaction.hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, notificationDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
const steps = [
|
|
||||||
getAccountTransactionsInBaseTransactionLedger,
|
|
||||||
getNextAndPreviousTransactions,
|
|
||||||
sortTransactions,
|
|
||||||
findPreviousAndNextTransactions
|
|
||||||
];
|
|
||||||
|
|
||||||
async.waterfall(steps, topCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a notification corresponding to the specified
|
|
||||||
* account and transaction identifier. Send errors back
|
|
||||||
* to the client using the res.json method or pass
|
|
||||||
* the notification json to the callback function.
|
|
||||||
*
|
|
||||||
* @param {Remote} $.remote
|
|
||||||
* @param {RippleAddress} req.params.account
|
|
||||||
* @param {Hex-encoded String} req.params.identifier
|
|
||||||
* @param {Express.js Response} res
|
|
||||||
* @param {Function} callback
|
|
||||||
*
|
|
||||||
* @callback
|
|
||||||
* @param {Error} error
|
|
||||||
* @param {Notification} notification
|
|
||||||
*/
|
|
||||||
function getNotificationHelper(api, account, identifier, urlBase, topCallback) {
|
|
||||||
|
|
||||||
function getTransaction(callback) {
|
|
||||||
try {
|
|
||||||
transactions.getTransaction(api, account, identifier, {}, callback);
|
|
||||||
} catch(err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkLedger(baseTransaction, callback) {
|
|
||||||
server.remoteHasLedger(api.remote, baseTransaction.ledger_index,
|
|
||||||
function(error, remoteHasLedger) {
|
|
||||||
if (error) {
|
|
||||||
return callback(error);
|
|
||||||
}
|
|
||||||
if (remoteHasLedger) {
|
|
||||||
callback(null, baseTransaction);
|
|
||||||
} else {
|
|
||||||
callback(new utils.common.errors.NotFoundError(
|
|
||||||
'Cannot Get Notification. ' +
|
|
||||||
'This transaction is not in the ripple\'s complete ledger set. ' +
|
|
||||||
'Because there is a gap in the rippled\'s historical database it ' +
|
|
||||||
'is not possible to determine the transactions that precede this one')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareNotificationDetails(baseTransaction, callback) {
|
|
||||||
const notificationDetails = {
|
|
||||||
account: account,
|
|
||||||
identifier: identifier,
|
|
||||||
transaction: baseTransaction
|
|
||||||
};
|
|
||||||
|
|
||||||
attachPreviousAndNextTransactionIdentifiers(api, notificationDetails,
|
|
||||||
callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatNotificationResponse(notificationDetails, callback) {
|
|
||||||
const notification = NotificationParser.parse(notificationDetails, urlBase);
|
|
||||||
callback(null, {notification: notification});
|
|
||||||
}
|
|
||||||
|
|
||||||
const steps = [
|
|
||||||
getTransaction,
|
|
||||||
checkLedger,
|
|
||||||
prepareNotificationDetails,
|
|
||||||
formatNotificationResponse
|
|
||||||
];
|
|
||||||
|
|
||||||
async.waterfall(steps, topCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a notification corresponding to the specified
|
|
||||||
* account and transaction identifier. Uses the res.json
|
|
||||||
* method to send errors or a notification back to the client.
|
|
||||||
*
|
|
||||||
* @param {Remote} $.remote
|
|
||||||
* @param {/lib/config-loader} $.config
|
|
||||||
* @param {RippleAddress} req.params.account
|
|
||||||
* @param {Hex-encoded String} req.params.identifier
|
|
||||||
*/
|
|
||||||
function getNotification(account, identifier, urlBase, callback) {
|
|
||||||
validate.address(account);
|
|
||||||
validate.identifier(identifier);
|
|
||||||
|
|
||||||
return getNotificationHelper(this, account, identifier, urlBase, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a notifications corresponding to the specified
|
|
||||||
* account.
|
|
||||||
*
|
|
||||||
* This function calls transactions.getAccountTransactions
|
|
||||||
* recursively to retrieve results_per_page number of transactions
|
|
||||||
* and filters the results using client-specified parameters.
|
|
||||||
*
|
|
||||||
* @param {RippleAddress} account
|
|
||||||
* @param {string} urlBase - The url to use for the transaction status URL
|
|
||||||
*
|
|
||||||
* @param {string} options.source_account
|
|
||||||
* @param {Number} options.ledger_min
|
|
||||||
* @param {Number} options.ledger_max
|
|
||||||
* @param {string} [false] options.earliest_first
|
|
||||||
* @param {string[]} options.types - @see transactions.getAccountTransactions
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
// TODO: If given ledger range, check for ledger gaps
|
|
||||||
function getNotifications(account, urlBase, options, callback) {
|
|
||||||
validate.address(account);
|
|
||||||
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
function getTransactions(_callback) {
|
|
||||||
|
|
||||||
const resultsPerPage = options.results_per_page ||
|
|
||||||
transactions.DEFAULT_RESULTS_PER_PAGE;
|
|
||||||
const offset = resultsPerPage * ((options.page || 1) - 1);
|
|
||||||
|
|
||||||
const args = {
|
|
||||||
account: account,
|
|
||||||
direction: options.direction,
|
|
||||||
min: resultsPerPage,
|
|
||||||
max: resultsPerPage,
|
|
||||||
ledger_index_min: options.ledger_min,
|
|
||||||
ledger_index_max: options.ledger_max,
|
|
||||||
offset: offset,
|
|
||||||
earliestFirst: options.earliest_first
|
|
||||||
};
|
|
||||||
|
|
||||||
transactions.getAccountTransactions(self, args, _callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseNotifications(baseTransactions, _callback) {
|
|
||||||
const numTransactions = baseTransactions.length;
|
|
||||||
|
|
||||||
function parseNotification(transaction, __callback) {
|
|
||||||
const args = {
|
|
||||||
account: account,
|
|
||||||
identifier: transaction.hash,
|
|
||||||
transaction: transaction
|
|
||||||
};
|
|
||||||
|
|
||||||
// Attaching previous and next identifiers
|
|
||||||
const idx = baseTransactions.indexOf(transaction);
|
|
||||||
const previous = baseTransactions[idx + 1];
|
|
||||||
const next = baseTransactions[idx - 1];
|
|
||||||
|
|
||||||
if (!options.earliest_first) {
|
|
||||||
args.previous_transaction_identifier = previous ?
|
|
||||||
previous.hash : undefined;
|
|
||||||
args.next_transaction_identifier = next ? next.hash : undefined;
|
|
||||||
} else {
|
|
||||||
args.previous_transaction_identifier = next ? next.hash : undefined;
|
|
||||||
args.next_transaction_identifier = previous ? previous.hash : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.previous_transaction_identifier = args.previous_hash;
|
|
||||||
args.next_transaction_identifier = args.next_hash;
|
|
||||||
|
|
||||||
const firstAndPaging = options.page &&
|
|
||||||
(options.earliest_first ?
|
|
||||||
args.previous_transaction_identifier === undefined :
|
|
||||||
args.next_transaction_identifier === undefined);
|
|
||||||
|
|
||||||
const last = idx === numTransactions - 1;
|
|
||||||
|
|
||||||
if (firstAndPaging || last) {
|
|
||||||
attachPreviousAndNextTransactionIdentifiers(self, args,
|
|
||||||
function(err, _args) {
|
|
||||||
return __callback(err, NotificationParser.parse(_args, urlBase));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return __callback(null, NotificationParser.parse(args, urlBase));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return async.map(baseTransactions, parseNotification, _callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatResponse(notifications, _callback) {
|
|
||||||
_callback(null, {notifications: notifications});
|
|
||||||
}
|
|
||||||
|
|
||||||
const steps = [
|
|
||||||
getTransactions,
|
|
||||||
_.partial(utils.attachDate, self),
|
|
||||||
parseNotifications,
|
|
||||||
formatResponse
|
|
||||||
];
|
|
||||||
|
|
||||||
return async.waterfall(steps, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getNotification: getNotification,
|
|
||||||
getNotifications: getNotifications
|
|
||||||
};
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/* @flow */
|
|
||||||
/* eslint-disable valid-jsdoc */
|
|
||||||
'use strict';
|
|
||||||
const ripple = require('../utils').common.core;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a Ripple transaction in the JSON format,
|
|
||||||
* along with some additional pieces of information,
|
|
||||||
* into a Notification object.
|
|
||||||
*
|
|
||||||
* @param {Ripple Transaction in JSON Format} notification_details.transaction
|
|
||||||
* @param {RippleAddress} notification_details.account
|
|
||||||
* @param {Hex-encoded String}
|
|
||||||
* notification_details.previous_transaction_identifier
|
|
||||||
* @param {Hex-encoded String}
|
|
||||||
* notification_details.next_transaction_identifier
|
|
||||||
*
|
|
||||||
* @returns {Notification}
|
|
||||||
*/
|
|
||||||
function NotificationParser() {}
|
|
||||||
|
|
||||||
NotificationParser.prototype.parse = function(notification_details, urlBase) {
|
|
||||||
const transaction = notification_details.transaction;
|
|
||||||
const account = notification_details.account;
|
|
||||||
const previous_transaction_identifier =
|
|
||||||
notification_details.previous_transaction_identifier;
|
|
||||||
const next_transaction_identifier =
|
|
||||||
notification_details.next_transaction_identifier;
|
|
||||||
|
|
||||||
const metadata = transaction.meta || { };
|
|
||||||
|
|
||||||
const notification = {
|
|
||||||
account: account,
|
|
||||||
type: transaction.TransactionType.toLowerCase(),
|
|
||||||
direction: '', // set below
|
|
||||||
state: (metadata.TransactionResult === 'tesSUCCESS'
|
|
||||||
? 'validated' : 'failed'),
|
|
||||||
result: metadata.TransactionResult || '',
|
|
||||||
ledger: '' + transaction.ledger_index,
|
|
||||||
hash: transaction.hash,
|
|
||||||
timestamp: '',// set below
|
|
||||||
transaction_url: '', // set below
|
|
||||||
previous_transaction_identifier:
|
|
||||||
notification_details.previous_transaction_identifier || '',
|
|
||||||
previous_notification_url: '', // set below
|
|
||||||
next_transaction_identifier:
|
|
||||||
notification_details.next_transaction_identifier || '',
|
|
||||||
next_notification_url: '' // set below
|
|
||||||
};
|
|
||||||
|
|
||||||
notification.timestamp = transaction.date ?
|
|
||||||
new Date(ripple.utils.time.fromRipple(transaction.date)).toISOString() : '';
|
|
||||||
|
|
||||||
// Direction
|
|
||||||
if (account === transaction.Account) {
|
|
||||||
notification.direction = 'outgoing';
|
|
||||||
} else if (transaction.TransactionType === 'Payment'
|
|
||||||
&& transaction.Destination !== account) {
|
|
||||||
notification.direction = 'passthrough';
|
|
||||||
} else {
|
|
||||||
notification.direction = 'incoming';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notification URL
|
|
||||||
|
|
||||||
if (notification.type === 'payment') {
|
|
||||||
notification.transaction_url = urlBase + '/v1/accounts/'
|
|
||||||
+ notification.account
|
|
||||||
+ '/payments/'
|
|
||||||
+ notification.hash;
|
|
||||||
} else if (notification.type === 'offercreate'
|
|
||||||
|| notification.type === 'offercancel') {
|
|
||||||
notification.type = 'order';
|
|
||||||
notification.transaction_url = urlBase + '/v1/accounts/'
|
|
||||||
+ notification.account
|
|
||||||
+ '/orders/' + notification.hash;
|
|
||||||
} else if (notification.type === 'trustset') {
|
|
||||||
notification.type = 'trustline';
|
|
||||||
notification.transaction_url = urlBase + '/v1/transactions/'
|
|
||||||
+ notification.hash;
|
|
||||||
} else if (notification.type === 'accountset') {
|
|
||||||
notification.type = 'settings';
|
|
||||||
notification.transaction_url = urlBase + '/v1/transactions/'
|
|
||||||
+ notification.hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next notification URL
|
|
||||||
|
|
||||||
if (next_transaction_identifier) {
|
|
||||||
notification.next_notification_url = urlBase + '/v1/accounts/'
|
|
||||||
+ notification.account + '/notifications/' + next_transaction_identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Previous notification URL
|
|
||||||
if (previous_transaction_identifier) {
|
|
||||||
notification.previous_notification_url = urlBase + '/v1/accounts/'
|
|
||||||
+ notification.account + '/notifications/'
|
|
||||||
+ previous_transaction_identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
return notification;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = new NotificationParser();
|
|
||||||
@@ -6,6 +6,7 @@ const utils = require('./utils');
|
|||||||
const parseTransaction = require('./parse/transaction');
|
const parseTransaction = require('./parse/transaction');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const errors = utils.common.errors;
|
const errors = utils.common.errors;
|
||||||
|
const composeAsync = utils.common.composeAsync;
|
||||||
|
|
||||||
const DEFAULT_LIMIT = 100;
|
const DEFAULT_LIMIT = 100;
|
||||||
const MIN_LEDGER_VERSION = 32570; // earlier versions have been completely lost
|
const MIN_LEDGER_VERSION = 32570; // earlier versions have been completely lost
|
||||||
@@ -81,7 +82,6 @@ function parseAccountTxTransaction(tx) {
|
|||||||
return parseTransaction(tx.tx);
|
return parseTransaction(tx.tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function transactionFilter(address, filters, tx) {
|
function transactionFilter(address, filters, tx) {
|
||||||
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
||||||
return false;
|
return false;
|
||||||
@@ -98,14 +98,20 @@ function transactionFilter(address, filters, tx) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function orderFilter(options, tx) {
|
||||||
|
return !options.startTx || (options.earliestFirst ?
|
||||||
|
utils.compareTransactions(tx, options.startTx) > 0 :
|
||||||
|
utils.compareTransactions(tx, options.startTx) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
function getAccountTx(remote, address, options, marker, limit, callback) {
|
function getAccountTx(remote, address, options, marker, limit, callback) {
|
||||||
const params = {
|
const params = {
|
||||||
account: address,
|
account: address,
|
||||||
ledger_index_min: options.ledgerVersion || options.minLedgerVersion || -1,
|
ledger_index_min: options.minLedgerVersion || -1,
|
||||||
ledger_index_max: options.ledgerVersion || options.maxLedgerVersion || -1,
|
ledger_index_max: options.maxLedgerVersion || -1,
|
||||||
forward: options.earliestFirst,
|
forward: options.earliestFirst,
|
||||||
binary: options.binary,
|
binary: options.binary,
|
||||||
limit: Math.min(limit || DEFAULT_LIMIT, 10),
|
limit: Math.max(limit || DEFAULT_LIMIT, 10),
|
||||||
marker: marker
|
marker: marker
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,20 +122,40 @@ function getAccountTx(remote, address, options, marker, limit, callback) {
|
|||||||
.filter((tx) => tx.validated)
|
.filter((tx) => tx.validated)
|
||||||
.map(parseAccountTxTransaction)
|
.map(parseAccountTxTransaction)
|
||||||
.filter(_.partial(transactionFilter, address, options))
|
.filter(_.partial(transactionFilter, address, options))
|
||||||
|
.filter(_.partial(orderFilter, options))
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAccountTransactions(address, options, callback) {
|
function getAccountTransactionsInternal(remote, address, options, callback) {
|
||||||
validate.address(address);
|
|
||||||
|
|
||||||
const limit = options.limit || DEFAULT_LIMIT;
|
const limit = options.limit || DEFAULT_LIMIT;
|
||||||
const compare = options.earliestFirst ? utils.compareTransactions :
|
const compare = options.earliestFirst ? utils.compareTransactions :
|
||||||
_.rearg(utils.compareTransactions, 1, 0);
|
_.rearg(utils.compareTransactions, 1, 0);
|
||||||
const getter = _.partial(getAccountTx, this.remote, address, options);
|
const getter = _.partial(getAccountTx, remote, address, options);
|
||||||
utils.getRecursive(getter, limit, (error, data) => {
|
utils.getRecursive(getter, limit,
|
||||||
return error ? callback(error) : callback(null, data.sort(compare));
|
composeAsync((txs) => txs.sort(compare), callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccountTransactions(address, options, callback) {
|
||||||
|
validate.address(address);
|
||||||
|
validate.getAccountTransactionsOptions(options);
|
||||||
|
|
||||||
|
const remote = this.remote;
|
||||||
|
if (options.start) {
|
||||||
|
getTransaction.bind(this)(options.start, {}, (error, tx) => {
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ledgerVersion = tx.outcome.ledgerVersion;
|
||||||
|
const ledgerOption = options.earliestFirst ?
|
||||||
|
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion};
|
||||||
|
const newOptions = _.assign({}, options, {startTx: tx}, ledgerOption);
|
||||||
|
getAccountTransactionsInternal(remote, address, newOptions, callback);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
getAccountTransactionsInternal(remote, address, options, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -101,6 +101,17 @@ describe('RippleAPI', function() {
|
|||||||
_.partial(checkResult, accountTransactionsResponse, done));
|
_.partial(checkResult, accountTransactionsResponse, done));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: this doesn't test much, just that it doesn't crash
|
||||||
|
it('getAccountTransactions with start option', function(done) {
|
||||||
|
const options = {
|
||||||
|
start: hashes.VALID_TRANSACTION_HASH,
|
||||||
|
earliestFirst: false,
|
||||||
|
limit: 2
|
||||||
|
};
|
||||||
|
this.api.getAccountTransactions(address, options,
|
||||||
|
_.partial(checkResult, accountTransactionsResponse, done));
|
||||||
|
});
|
||||||
|
|
||||||
it('getTrustlines', function(done) {
|
it('getTrustlines', function(done) {
|
||||||
const options = {currency: 'USD'};
|
const options = {currency: 'USD'};
|
||||||
this.api.getTrustlines(address, options,
|
this.api.getTrustlines(address, options,
|
||||||
|
|||||||
Reference in New Issue
Block a user