From c06c74e46076fb021ebb541637dfe3acc7513df2 Mon Sep 17 00:00:00 2001 From: Stefan Thomas Date: Wed, 31 Jul 2013 19:54:07 -0700 Subject: [PATCH] Basic implementation for new path finding API. --- src/js/ripple/pathfind.js | 78 +++++++++++++++++++++++++++++++++++++++ src/js/ripple/remote.js | 70 +++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/js/ripple/pathfind.js diff --git a/src/js/ripple/pathfind.js b/src/js/ripple/pathfind.js new file mode 100644 index 00000000..6dba8579 --- /dev/null +++ b/src/js/ripple/pathfind.js @@ -0,0 +1,78 @@ +var EventEmitter = require('events').EventEmitter; +var util = require('util'); + +var Amount = require('./amount').Amount; + +var extend = require('extend'); + +/** + * Represents a persistent path finding request. + * + * Only one path find request is allowed per connection, so when another path + * find request is triggered it will supercede the existing one, making it emit + * the 'end' and 'superceded' events. + */ +var PathFind = function (remote, src_account, dst_account, + dst_amount, src_currencies) +{ + EventEmitter.call(this); + + this.remote = remote; + + this.src_account = src_account; + this.dst_account = dst_account; + this.dst_amount = dst_amount; + this.src_currencies = src_currencies; +}; + +util.inherits(PathFind, EventEmitter); + +/** + * Submits a path_find_create request to the network. + * + * This starts a path find request, superceding all previous path finds. + * + * This will be called automatically by Remote when this object is instantiated, + * so you should only have to call it if the path find was closed or superceded + * and you wish to restart it. + */ +PathFind.prototype.create = function () +{ + var req = this.remote.request_path_find_create(this.src_account, + this.dst_account, + this.dst_amount, + this.src_currencies); + + req.request(); +}; + +PathFind.prototype.close = function () +{ + this.remote.request_path_find_close().request(); + this.emit('end'); + this.emit('close'); +}; + +PathFind.prototype.notify_update = function (message) +{ + var src_account = message.source_account; + var dst_account = message.destination_account; + var dst_amount = Amount.from_json(message.destination_amount); + + // Only pass the event along if this path find response matches what we were + // looking for. + if (message.alternatives && message.alternatives.length) console.log(Amount.from_json(message.alternatives[0].source_amount).to_text_full()); + if (this.src_account === src_account && + this.dst_account === dst_account && + this.dst_amount.equals(dst_amount)) { + this.emit('update', message); + } +}; + +PathFind.prototype.notify_superceded = function () +{ + this.emit('end'); + this.emit('superceded'); +}; + +exports.PathFind = PathFind; diff --git a/src/js/ripple/remote.js b/src/js/ripple/remote.js index 6606e7d5..0d11a8a7 100644 --- a/src/js/ripple/remote.js +++ b/src/js/ripple/remote.js @@ -26,6 +26,7 @@ var Transaction = require('./transaction').Transaction; var Account = require('./account').Account; var Meta = require('./meta').Meta; var OrderBook = require('./orderbook').OrderBook; +var PathFind = require('./pathfind').PathFind; var utils = require('./utils'); var config = require('./config'); @@ -348,6 +349,7 @@ function Remote(opts, trace) { this._connected = false; this._last_tx = null; + this._cur_path_find = null; // Local signing implies local fees and sequences if (this.local_signing) { @@ -655,6 +657,15 @@ Remote.prototype._handle_message = function (json) { this.emit('transaction_all', message); break; + case 'path_find': + // Pass the event to the currently open PathFind object + if (this._cur_path_find) { + this._cur_path_find.notify_update(message); + } + + this.emit('path_find_all', message); + break; + // XXX Should be tracked by the Server object case 'serverStatus': if ('load_base' in message && 'load_factor' in message && @@ -1214,6 +1225,24 @@ Remote.prototype.account = function (accountId, callback) { return account; }; +Remote.prototype.path_find = function (src_account, dst_account, + dst_amount, src_currencies) +{ + var path_find = new PathFind(this, + src_account, dst_account, + dst_amount, src_currencies); + + if (this._cur_path_find) { + this._cur_path_find.notify_superceded(); + } + + path_find.create(); + + this._cur_path_find = path_find; + + return path_find; +}; + Remote.prototype.book = function (currency_gets, issuer_gets, currency_pays, issuer_pays) { var gets = currency_gets; @@ -1385,6 +1414,47 @@ Remote.prototype.request_ripple_path_find = function (src_account, dst_account, return request; }; +Remote.prototype.request_path_find_create = function (src_account, dst_account, + dst_amount, + src_currencies, callback) +{ + var self = this; + var request = new Request(this, 'path_find'); + + request.message.subcommand = 'create'; + request.message.source_account = UInt160.json_rewrite(src_account); + request.message.destination_account = UInt160.json_rewrite(dst_account); + request.message.destination_amount = Amount.json_rewrite(dst_amount); + + if (src_currencies) { + request.message.source_currencies = src_currencies.map(function (ci) { + var ci_new = {}; + + if ('issuer' in ci) + ci_new.issuer = UInt160.json_rewrite(ci.issuer); + + if ('currency' in ci) + ci_new.currency = Currency.json_rewrite(ci.currency); + + return ci_new; + }); + } + + request.callback(callback); + + return request; +}; + +Remote.prototype.request_path_find_close = function () +{ + var self = this; + var request = new Request(this, 'path_find'); + + request.message.subcommand = 'close'; + + return request; +}; + Remote.prototype.request_unl_list = function (callback) { var request = new Request(this, 'unl_list'); request.callback(callback);