api/notifications.js
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) {
    var 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);
  }

  // All we care about is the count of the transactions
  function countAccountTransactionsInBaseTransactionledger(txns, callback) {
    callback(null, txns.length);
  }

  // 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(numTransactionsInLedger, callback) {
    async.concat([false, true], function(earliestFirst, concat_callback) {
      var 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);

    var 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
    var baseTransactionIndex = _.findIndex(txns, function(possibility) {
      if (possibility.hash === notificationDetails.transaction.hash) {
        return true;
      } else if (possibility.client_resource_id &&
        (possibility.client_resource_id ===
          notificationDetails.transaction.client_resource_id ||
        possibility.client_resource_id === notificationDetails.identifier)) {
        return true;
      }
      return false;
    });

    // The previous transaction is the one with an index in
    // the array of baseTransactionIndex - 1
    if (baseTransactionIndex > 0) {
      var previous_transaction = txns[baseTransactionIndex - 1];
      notificationDetails.previous_transaction_identifier =
        (previous_transaction.from_local_db ?
          previous_transaction.client_resource_id : previous_transaction.hash);
      notificationDetails.previous_hash = previous_transaction.hash;
    }

    // The next transaction is the one with an index in
    // the array of baseTransactionIndex + 1
    if (baseTransactionIndex + 1 < txns.length) {
      var next_transaction = txns[baseTransactionIndex + 1];
      notificationDetails.next_transaction_identifier =
        (next_transaction.from_local_db ?
            next_transaction.client_resource_id : next_transaction.hash);
      notificationDetails.next_hash = next_transaction.hash;
    }

    callback(null, notificationDetails);
  }

  var steps = [
    getAccountTransactionsInBaseTransactionLedger,
    countAccountTransactionsInBaseTransactionledger,
    getNextAndPreviousTransactions,
    sortTransactions,
    findPreviousAndNextTransactions
  ];

  async.waterfall(steps, topCallback);
}
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) {
    var 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);
  }

  // All we care about is the count of the transactions
  function countAccountTransactionsInBaseTransactionledger(txns, callback) {
    callback(null, txns.length);
  }

  // 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(numTransactionsInLedger, callback) {
    async.concat([false, true], function(earliestFirst, concat_callback) {
      var 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);

    var 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
    var baseTransactionIndex = _.findIndex(txns, function(possibility) {
      if (possibility.hash === notificationDetails.transaction.hash) {
        return true;
      } else if (possibility.client_resource_id &&
        (possibility.client_resource_id ===
          notificationDetails.transaction.client_resource_id ||
        possibility.client_resource_id === notificationDetails.identifier)) {
        return true;
      }
      return false;
    });

    // The previous transaction is the one with an index in
    // the array of baseTransactionIndex - 1
    if (baseTransactionIndex > 0) {
      var previous_transaction = txns[baseTransactionIndex - 1];
      notificationDetails.previous_transaction_identifier =
        (previous_transaction.from_local_db ?
          previous_transaction.client_resource_id : previous_transaction.hash);
      notificationDetails.previous_hash = previous_transaction.hash;
    }

    // The next transaction is the one with an index in
    // the array of baseTransactionIndex + 1
    if (baseTransactionIndex + 1 < txns.length) {
      var next_transaction = txns[baseTransactionIndex + 1];
      notificationDetails.next_transaction_identifier =
        (next_transaction.from_local_db ?
            next_transaction.client_resource_id : next_transaction.hash);
      notificationDetails.next_hash = next_transaction.hash;
    }

    callback(null, notificationDetails);
  }

  var steps = [
    getAccountTransactionsInBaseTransactionLedger,
    countAccountTransactionsInBaseTransactionledger,
    getNextAndPreviousTransactions,
    sortTransactions,
    findPreviousAndNextTransactions
  ];

  async.waterfall(steps, topCallback);
}
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 ) { var 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 ) ; } // All we care about is the count of the transactions function countAccountTransactionsInBaseTransactionledger ( txns , callback ) { callback ( null , txns . length ) ; } // 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 ( numTransactionsInLedger , callback ) { async . concat ( [ false , true ] , function ( earliestFirst , concat_callback ) { var 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 ) ; var 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 var baseTransactionIndex = _ . findIndex ( txns , function ( possibility ) { if ( possibility . hash === notificationDetails . transaction . hash ) { return true ; } else if ( possibility . client_resource_id && ( possibility . client_resource_id === notificationDetails . transaction . client_resource_id || possibility . client_resource_id === notificationDetails . identifier ) ) { return true ; } return false ; } ) ; // The previous transaction is the one with an index in // the array of baseTransactionIndex - 1 if ( baseTransactionIndex > 0 ) { var previous_transaction = txns [ baseTransactionIndex - 1 ] ; notificationDetails . previous_transaction_identifier = ( previous_transaction . from_local_db ? previous_transaction . client_resource_id : previous_transaction . hash ) ; notificationDetails . previous_hash = previous_transaction . hash ; } // The next transaction is the one with an index in // the array of baseTransactionIndex + 1 if ( baseTransactionIndex + 1 < txns . length ) { var next_transaction = txns [ baseTransactionIndex + 1 ] ; notificationDetails . next_transaction_identifier = ( next_transaction . from_local_db ? next_transaction . client_resource_id : next_transaction . hash ) ; notificationDetails . next_hash = next_transaction . hash ; } callback ( null , notificationDetails ) ; } var steps = [ getAccountTransactionsInBaseTransactionLedger , countAccountTransactionsInBaseTransactionledger , getNextAndPreviousTransactions , sortTransactions , findPreviousAndNextTransactions ] ; async . waterfall ( steps , topCallback ) ; }
Find the previous and next transaction hashes or
client_resource_ids using both the rippled and
local database. Report errors to the client using res.json
or pass the notificationDetails with the added fields
back to the callback.

@param {Remote} $.remote
@param {/lib/db-interface} $.dbinterface
@param {Express.js Response} res
@param {RippleAddress} notificationDetails.account
@param {Ripple Transaction in JSON Format} notificationDetails.transaction
@param {Hex-encoded String|ResourceId} notificationDetails.identifier
@param {Function} callback

@callback
@param {Error} error
@param {Object} notificationDetails
Find the previous and next transaction hashes or client_resource_ids using both the rippled and local database . Report errors to the client using res . json or pass the notificationDetails with the added fields back to the callback .