Merge branch 'master' of github.com:jedmccaleb/NewCoin

This commit is contained in:
jed
2012-11-10 16:08:08 -08:00
8 changed files with 432 additions and 328 deletions

View File

@@ -28,6 +28,19 @@ public:
virtual ~InfoSub() { ; }
virtual void send(const Json::Value& jvObj) = 0;
protected:
boost::unordered_set<RippleAddress> mSubAccountInfo;
boost::unordered_set<RippleAddress> mSubAccountTransaction;
boost::mutex mLock;
public:
void insertSubAccountInfo(RippleAddress addr)
{
boost::mutex::scoped_lock sl(mLock);
mSubAccountInfo.insert(addr);
}
};
class NetworkOPs

View File

@@ -51,6 +51,7 @@ Json::Value RPCHandler::rpcError(int iError)
{ rpcNO_ACCOUNT, "noAccount", "No such account." },
{ rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." },
{ rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." },
{ rpcNO_EVENTS, "noEvents", "Current transport does not support events." },
{ rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." },
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
@@ -92,6 +93,13 @@ Json::Value RPCHandler::rpcError(int iError)
RPCHandler::RPCHandler(NetworkOPs* netOps)
{
mNetOps=netOps;
mInfoSub=NULL;
}
RPCHandler::RPCHandler(NetworkOPs* netOps, InfoSub* infoSub)
{
mNetOps=netOps;
mInfoSub=infoSub;
}
int RPCHandler::getParamCount(const Json::Value& params)
@@ -1309,53 +1317,58 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
int iMinParams;
int iMaxParams;
bool mAdminRequired;
bool mEvented;
unsigned int iOptions;
} commandsA[] = {
// Request-response methods
{ "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true },
{ "account_info", &RPCHandler::doAccountInfo, 1, 2, false, optCurrent },
{ "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, optNetwork },
{ "connect", &RPCHandler::doConnect, 1, 2, true },
{ "data_delete", &RPCHandler::doDataDelete, 1, 1, true },
{ "data_fetch", &RPCHandler::doDataFetch, 1, 1, true },
{ "data_store", &RPCHandler::doDataStore, 2, 2, true },
{ "get_counts", &RPCHandler::doGetCounts, 0, 1, true },
{ "ledger", &RPCHandler::doLedger, 0, 2, false, optNetwork },
{ "ledger_accept", &RPCHandler::doLedgerAccept, 0, 0, true, optCurrent },
{ "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, optClosed },
{ "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, optCurrent },
{ "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, optCurrent },
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
{ "logrotate", &RPCHandler::doLogRotate, 0, 0, true },
{ "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, optCurrent },
{ "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, optCurrent },
{ "account_info", &RPCHandler::doAccountInfo, 1, 2, false, false, optCurrent },
{ "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, false, optNetwork },
{ "connect", &RPCHandler::doConnect, 1, 2, true },
{ "data_delete", &RPCHandler::doDataDelete, 1, 1, true },
{ "data_fetch", &RPCHandler::doDataFetch, 1, 1, true },
{ "data_store", &RPCHandler::doDataStore, 2, 2, true },
{ "get_counts", &RPCHandler::doGetCounts, 0, 1, true },
{ "ledger", &RPCHandler::doLedger, 0, 2, false, false, optNetwork },
{ "ledger_accept", &RPCHandler::doLedgerAccept, 0, 0, true, false, optCurrent },
{ "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, false, optClosed },
{ "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, false, optCurrent },
{ "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, false, optCurrent },
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
{ "logrotate", &RPCHandler::doLogRotate, 0, 0, true },
{ "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, false, optCurrent },
{ "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, false, optCurrent },
{ "peers", &RPCHandler::doPeers, 0, 0, true },
{ "profile", &RPCHandler::doProfile, 1, 9, false, optCurrent },
{ "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, optCurrent },
{ "submit", &RPCHandler::doSubmit, 2, 2, false, optCurrent },
{ "submit_json", &RPCHandler::doSubmitJson, -1, -1, false, optCurrent },
{ "server_info", &RPCHandler::doServerInfo, 0, 0, true },
{ "stop", &RPCHandler::doStop, 0, 0, true },
{ "transaction_entry", &RPCHandler::doTransactionEntry, -1, -1, false, optCurrent },
{ "tx", &RPCHandler::doTx, 1, 1, true },
{ "tx_history", &RPCHandler::doTxHistory, 1, 1, false, },
{ "profile", &RPCHandler::doProfile, 1, 9, false, false, optCurrent },
{ "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, false, optCurrent },
{ "submit", &RPCHandler::doSubmit, 2, 2, false, false, optCurrent },
{ "submit_json", &RPCHandler::doSubmitJson, -1, -1, false, false, optCurrent },
{ "server_info", &RPCHandler::doServerInfo, 0, 0, true },
{ "stop", &RPCHandler::doStop, 0, 0, true },
{ "transaction_entry", &RPCHandler::doTransactionEntry, -1, -1, false, false, optCurrent },
{ "tx", &RPCHandler::doTx, 1, 1, true },
{ "tx_history", &RPCHandler::doTxHistory, 1, 1, false, },
{ "unl_add", &RPCHandler::doUnlAdd, 1, 2, true },
{ "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true },
{ "unl_list", &RPCHandler::doUnlList, 0, 0, true },
{ "unl_load", &RPCHandler::doUnlLoad, 0, 0, true },
{ "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true },
{ "unl_reset", &RPCHandler::doUnlReset, 0, 0, true },
{ "unl_score", &RPCHandler::doUnlScore, 0, 0, true },
{ "unl_add", &RPCHandler::doUnlAdd, 1, 2, true },
{ "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true },
{ "unl_list", &RPCHandler::doUnlList, 0, 0, true },
{ "unl_load", &RPCHandler::doUnlLoad, 0, 0, true },
{ "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true },
{ "unl_reset", &RPCHandler::doUnlReset, 0, 0, true },
{ "unl_score", &RPCHandler::doUnlScore, 0, 0, true },
{ "validation_create", &RPCHandler::doValidationCreate, 0, 1, false },
{ "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false },
{ "validation_create", &RPCHandler::doValidationCreate, 0, 1, false },
{ "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false },
{ "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, optCurrent },
{ "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, },
{ "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, },
{ "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, false, optCurrent },
{ "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, },
{ "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, },
{ "login", &RPCHandler::doLogin, 2, 2, true },
};
{ "login", &RPCHandler::doLogin, 2, 2, true },
// Evented methods
{ "subscribe", &RPCHandler::doSubscribe, -1, -1, false, true },
{ "unsubscribe", &RPCHandler::doUnsubscribe, -1, -1, false, true }, };
int i = NUMBER(commandsA);
@@ -1370,6 +1383,10 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
{
return rpcError(rpcNO_PERMISSION);
}
else if (commandsA[i].mEvented && mInfoSub == NULL)
{
return rpcError(rpcNO_EVENTS);
}
else if (commandsA[i].iMinParams >= 0
? commandsA[i].iMaxParams
? (params.size() < commandsA[i].iMinParams
@@ -1933,4 +1950,183 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& jvRequest)
return jvResult;
}
boost::unordered_set<RippleAddress> RPCHandler::parseAccountIds(const Json::Value& jvArray)
{
boost::unordered_set<RippleAddress> usnaResult;
for (Json::Value::const_iterator it = jvArray.begin(); it != jvArray.end(); it++)
{
RippleAddress naString;
if (!(*it).isString() || !naString.setAccountID((*it).asString()))
{
usnaResult.clear();
break;
}
else
{
(void) usnaResult.insert(naString);
}
}
return usnaResult;
}
/*
server : Sends a message anytime the server status changes such as network connectivity.
ledger : Sends a message at every ledger close.
transactions : Sends a message for every transaction that makes it into a ledger.
rt_transactions
accounts
rt_accounts
*/
Json::Value RPCHandler::doSubscribe(const Json::Value& jvRequest)
{
Json::Value jvResult(Json::objectValue);
if (jvRequest.isMember("streams"))
{
for (Json::Value::iterator it = jvRequest["streams"].begin(); it != jvRequest["streams"].end(); it++)
{
if ((*it).isString())
{
std::string streamName=(*it).asString();
if(streamName=="server")
{
mNetOps->subServer(mInfoSub, jvResult);
}else if(streamName=="ledger")
{
mNetOps->subLedger(mInfoSub, jvResult);
}else if(streamName=="transactions")
{
mNetOps->subTransactions(mInfoSub);
}else if(streamName=="rt_transactions")
{
mNetOps->subRTTransactions(mInfoSub);
}else
{
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
}
}else
{
jvResult["error"] = "malformedSteam";
}
}
}
if (jvRequest.isMember("rt_accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["rt_accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mInfoSub->insertSubAccountInfo(naAccountID);
}
mNetOps->subAccount(mInfoSub, usnaAccoundIds, true);
}
}
if (jvRequest.isMember("accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mInfoSub->insertSubAccountInfo(naAccountID);
}
mNetOps->subAccount(mInfoSub, usnaAccoundIds, false);
}
}
return jvResult;
}
Json::Value RPCHandler::doUnsubscribe(const Json::Value& jvRequest)
{
Json::Value jvResult(Json::objectValue);
if (jvRequest.isMember("streams"))
{
for (Json::Value::iterator it = jvRequest["streams"].begin(); it != jvRequest["streams"].end(); it++)
{
if ((*it).isString() )
{
std::string streamName=(*it).asString();
if(streamName=="server")
{
mNetOps->unsubServer(mInfoSub);
}else if(streamName=="ledger")
{
mNetOps->unsubLedger(mInfoSub);
}else if(streamName=="transactions")
{
mNetOps->unsubTransactions(mInfoSub);
}else if(streamName=="rt_transactions")
{
mNetOps->unsubRTTransactions(mInfoSub);
}else
{
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
}
}else
{
jvResult["error"] = "malformedSteam";
}
}
}
if (jvRequest.isMember("rt_accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["rt_accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mInfoSub->insertSubAccountInfo(naAccountID);
}
mNetOps->unsubAccount(mInfoSub, usnaAccoundIds,true);
}
}
if (jvRequest.isMember("accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mInfoSub->insertSubAccountInfo(naAccountID);
}
mNetOps->unsubAccount(mInfoSub, usnaAccoundIds,false);
}
}
return jvResult;
}
// vim:ts=4

View File

@@ -6,7 +6,8 @@ class NetworkOPs;
class RPCHandler
{
NetworkOPs* mNetOps;
NetworkOPs* mNetOps;
InfoSub* mInfoSub;
typedef Json::Value (RPCHandler::*doFuncPtr)(const Json::Value &params);
enum {
@@ -15,6 +16,9 @@ class RPCHandler
optClosed = 4+optNetwork, // Need closed ledger
};
// Utilities
void addSubmitPath(Json::Value& txJSON);
boost::unordered_set<RippleAddress> parseAccountIds(const Json::Value& jvArray);
int getParamCount(const Json::Value& params);
bool extractString(std::string& param, const Json::Value& params, int index);
@@ -84,8 +88,9 @@ class RPCHandler
Json::Value doLedgerEntry(const Json::Value& params);
Json::Value doTransactionEntry(const Json::Value& params);
Json::Value doSubscribe(const Json::Value& params);
Json::Value doUnsubscribe(const Json::Value& params);
void addSubmitPath(Json::Value& txJSON);
public:
@@ -95,6 +100,7 @@ public:
// Misc failure
rpcLOAD_FAILED,
rpcNO_PERMISSION,
rpcNO_EVENTS,
rpcNOT_STANDALONE,
// Networking
@@ -151,8 +157,9 @@ public:
enum { GUEST, USER, ADMIN };
RPCHandler(NetworkOPs* netOps);
RPCHandler(NetworkOPs* netOps, InfoSub* infoSub);
Json::Value doCommand(const std::string& command, Json::Value& params,int role);
Json::Value doCommand(const std::string& command, Json::Value& params, int role);
Json::Value rpcError(int iError);
Json::Value handleJSONSubmit(const Json::Value& jvRequest);

View File

@@ -26,7 +26,7 @@ SETUP_LOG();
#endif
RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwork)
: mNetOps(nopNetwork), mRPCHandler(nopNetwork), mSocket(io_service)
: mNetOps(nopNetwork), mSocket(io_service)
{
mRole = RPCHandler::GUEST;
@@ -142,6 +142,8 @@ std::string RPCServer::handleRequest(const std::string& requestStr)
else if (!valParams.isArray())
return(HTTPReply(400, "params unparseable"));
RPCHandler mRPCHandler(mNetOps);
cLog(lsTRACE) << valParams;
Json::Value result = mRPCHandler.doCommand(strMethod, valParams,mRole);
cLog(lsTRACE) << result;

View File

@@ -22,9 +22,7 @@ public:
private:
NetworkOPs* mNetOps;
RPCHandler mRPCHandler;
boost::asio::ip::tcp::socket mSocket;

View File

@@ -18,8 +18,8 @@ WSConnection::~WSConnection()
mNetwork.unsubRTTransactions(this);
mNetwork.unsubLedger(this);
mNetwork.unsubServer(this);
mNetwork.unsubAccount(this, mSubAccountInfo,true);
mNetwork.unsubAccount(this, mSubAccountInfo,false);
mNetwork.unsubAccount(this, mSubAccountInfo, true);
mNetwork.unsubAccount(this, mSubAccountInfo, false);
}
void WSConnection::send(const Json::Value& jvObj)
@@ -33,17 +33,6 @@ void WSConnection::send(const Json::Value& jvObj)
Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
{
static struct {
const char* pCommand;
doFuncPtr dfpFunc;
} commandsA[] = {
// Request-Response Commands:
{ "submit", &WSConnection::doSubmit },
{ "subscribe", &WSConnection::doSubscribe },
{ "unsubscribe", &WSConnection::doUnsubscribe },
{ "rpc", &WSConnection::doRPC },
};
if (!jvRequest.isMember("command"))
{
Json::Value jvResult(Json::objectValue);
@@ -56,22 +45,27 @@ Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
return jvResult;
}
std::string strCommand = jvRequest["command"].asString();
int i = NUMBER(commandsA);
while (i-- && strCommand != commandsA[i].pCommand)
;
RPCHandler mRPCHandler(&mNetwork, this);
Json::Value jvResult(Json::objectValue);
if (i < 0)
// Regular RPC command
jvResult["result"] = mRPCHandler.doCommand(
jvRequest["command"].asString(),
jvRequest.isMember("params")
? jvRequest["params"]
: jvRequest,
mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
// Currently we will simply unwrap errors returned by the RPC
// API, in the future maybe we can make the responses
// consistent.
if (jvResult["result"].isObject() && jvResult["result"].isMember("error"))
{
jvResult["error"] = "unknownCommand"; // Unknown command.
}
else
{
(this->*(commandsA[i].dfpFunc))(jvResult, jvRequest);
jvResult = jvResult["result"];
jvResult["status"] = "error";
jvResult["request"] = jvRequest;
} else {
jvResult["status"] = "success";
}
if (jvRequest.isMember("id"))
@@ -79,237 +73,9 @@ Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
jvResult["id"] = jvRequest["id"];
}
if (jvResult.isMember("error"))
{
jvResult["result"] = "error";
jvResult["request"] = jvRequest;
}
else
{
jvResult["result"] = "success";
}
jvResult["type"] = "response";
jvResult["type"] = "response";
return jvResult;
}
boost::unordered_set<RippleAddress> WSConnection::parseAccountIds(const Json::Value& jvArray)
{
boost::unordered_set<RippleAddress> usnaResult;
for (Json::Value::const_iterator it = jvArray.begin(); it != jvArray.end(); it++)
{
RippleAddress naString;
if (!(*it).isString() || !naString.setAccountID((*it).asString()))
{
usnaResult.clear();
break;
}
else
{
(void) usnaResult.insert(naString);
}
}
return usnaResult;
}
//
// Commands
//
/*
server : Sends a message anytime the server status changes such as network connectivity.
ledger : Sends a message at every ledger close.
transactions : Sends a message for every transaction that makes it into a ledger.
rt_transactions
accounts
rt_accounts
*/
void WSConnection::doSubscribe(Json::Value& jvResult, Json::Value& jvRequest)
{
if (jvRequest.isMember("streams"))
{
for (Json::Value::iterator it = jvRequest["streams"].begin(); it != jvRequest["streams"].end(); it++)
{
if ((*it).isString())
{
std::string streamName=(*it).asString();
if(streamName=="server")
{
mNetwork.subServer(this, jvResult);
}else if(streamName=="ledger")
{
mNetwork.subLedger(this, jvResult);
}else if(streamName=="transactions")
{
mNetwork.subTransactions(this);
}else if(streamName=="rt_transactions")
{
mNetwork.subRTTransactions(this);
}else
{
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
}
}else
{
jvResult["error"] = "malformedSteam";
}
}
}
if (jvRequest.isMember("rt_accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["rt_accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
boost::mutex::scoped_lock sl(mLock);
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mSubAccountInfo.insert(naAccountID);
}
mNetwork.subAccount(this, usnaAccoundIds,true);
}
}
if (jvRequest.isMember("accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
boost::mutex::scoped_lock sl(mLock);
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mSubAccountInfo.insert(naAccountID);
}
mNetwork.subAccount(this, usnaAccoundIds,false);
}
}
}
void WSConnection::doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest)
{
if (jvRequest.isMember("streams"))
{
for (Json::Value::iterator it = jvRequest["streams"].begin(); it != jvRequest["streams"].end(); it++)
{
if ((*it).isString() )
{
std::string streamName=(*it).asString();
if(streamName=="server")
{
mNetwork.unsubServer(this);
}else if(streamName=="ledger")
{
mNetwork.unsubLedger(this);
}else if(streamName=="transactions")
{
mNetwork.unsubTransactions(this);
}else if(streamName=="rt_transactions")
{
mNetwork.unsubRTTransactions(this);
}else
{
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
}
}else
{
jvResult["error"] = "malformedSteam";
}
}
}
if (jvRequest.isMember("rt_accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["rt_accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
boost::mutex::scoped_lock sl(mLock);
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mSubAccountInfo.insert(naAccountID);
}
mNetwork.unsubAccount(this, usnaAccoundIds,true);
}
}
if (jvRequest.isMember("accounts"))
{
boost::unordered_set<RippleAddress> usnaAccoundIds = parseAccountIds(jvRequest["accounts"]);
if (usnaAccoundIds.empty())
{
jvResult["error"] = "malformedAccount";
}else
{
boost::mutex::scoped_lock sl(mLock);
BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
{
mSubAccountInfo.insert(naAccountID);
}
mNetwork.unsubAccount(this, usnaAccoundIds,false);
}
}
}
void WSConnection::doRPC(Json::Value& jvResult, Json::Value& jvRequest)
{
if (jvRequest.isMember("rpc_command") )
{
jvResult = theApp->getRPCHandler().doCommand(
jvRequest["rpc_command"].asString(),
jvRequest.isMember("params")
? jvRequest["params"]
: jvRequest,
mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
jvResult["type"] = "response";
}
else
{
jvResult["error"] = "fieldNotCommand";
}
}
// XXX Currently requires secret. Allow signed transaction as an alternative.
void WSConnection::doSubmit(Json::Value& jvResult, Json::Value& jvRequest)
{
if (!jvRequest.isMember("tx_json"))
{
jvResult["error"] = "fieldNotFoundTxJson";
}else if (!jvRequest.isMember("secret"))
{
jvResult["error"] = "fieldNotFoundSecret";
}else
{
jvResult=theApp->getRPCHandler().handleJSONSubmit(jvRequest);
// TODO: track the transaction mNetwork.subSubmit(this, jvResult["tx hash"] );
}
}
// vim:ts=4

View File

@@ -21,10 +21,6 @@ public:
protected:
typedef void (WSConnection::*doFuncPtr)(Json::Value& jvResult, Json::Value &jvRequest);
boost::mutex mLock;
boost::unordered_set<RippleAddress> mSubAccountInfo;
boost::unordered_set<RippleAddress> mSubAccountTransaction;
WSServerHandler<websocketpp::WSDOOR_SERVER>* mHandler;
connection_ptr mConnection;
NetworkOPs& mNetwork;
@@ -44,13 +40,6 @@ public:
// Utilities
Json::Value invokeCommand(Json::Value& jvRequest);
boost::unordered_set<RippleAddress> parseAccountIds(const Json::Value& jvArray);
// Commands
void doSubmit(Json::Value& jvResult, Json::Value& jvRequest);
void doRPC(Json::Value& jvResult, Json::Value& jvRequest);
void doSubscribe(Json::Value& jvResult, Json::Value& jvRequest);
void doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest);
};

View File

@@ -147,6 +147,21 @@ Request.prototype.ripple_state = function (account, issuer, currency) {
return this;
};
Request.prototype.accounts = function (accounts) {
if ("object" !== typeof accounts) {
accounts = [accounts];
}
// Process accounts parameters
var procAccounts = [];
for (var i = 0, l = accounts.length; i < l; i++) {
procAccounts.push(UInt160.json_rewrite(accounts[i]));
}
this.message.accounts = procAccounts;
return this;
};
//
// Remote - access to a remote Ripple server via websocket.
//
@@ -429,13 +444,13 @@ Remote.prototype._connect_message = function (ws, json) {
if (!request) {
unexpected = true;
}
else if ('success' === message.result) {
if (this.trace) console.log("message: %s", json);
else if ('success' === message.status) {
if (this.trace) console.log("remote: response: %s", json);
request.emit('success', message);
request.emit('success', message.result);
}
else if (message.error) {
if (this.trace) console.log("message: %s", json);
if (this.trace) console.log("remote: error: %s", json);
request.emit('error', {
'error' : 'remoteError',
@@ -509,13 +524,33 @@ Remote.prototype.request = function (request) {
}
};
Remote.prototype.request_server_info = function () {
var request = new Request(this, 'rpc');
request.message.command = 'server_info';
return request;
};
Remote.prototype.request_ledger = function (params) {
// XXX Does this require the server to be trusted?
//assert(this.trusted);
var request = new Request(this, 'rpc');
request.message.command = 'ledger';
request.message.params = params;
return request;
};
// Only for unit testing.
Remote.prototype.request_ledger_hash = function () {
assert(this.trusted); // If not trusted, need to check proof.
var request = new Request(this, 'rpc');
request.message.rpc_command = 'ledger_closed';
request.message.command = 'ledger_closed';
return request;
};
@@ -525,7 +560,7 @@ Remote.prototype.request_ledger_hash = function () {
Remote.prototype.request_ledger_current = function () {
var request = new Request(this, 'rpc');
request.message.rpc_command = 'ledger_current';
request.message.command = 'ledger_current';
return request;
};
@@ -540,7 +575,7 @@ Remote.prototype.request_ledger_entry = function (type) {
var self = this;
var request = new Request(this, 'rpc');
request.message.rpc_command = 'ledger_entry';
request.message.command = 'ledger_entry';
if (type)
this.type = type;
@@ -593,10 +628,28 @@ Remote.prototype.request_ledger_entry = function (type) {
return request;
};
Remote.prototype.request_subscribe = function () {
Remote.prototype.request_subscribe = function (streams) {
var request = new Request(this, 'subscribe');
request.message.streams = [ 'ledger', 'server' ];
if (streams) {
if ("object" !== typeof streams) {
streams = [streams];
}
request.message.streams = streams;
}
return request;
};
Remote.prototype.request_unsubscribe = function (streams) {
var request = new Request(this, 'unsubscribe');
if (streams) {
if ("object" !== typeof streams) {
streams = [streams];
}
request.message.streams = streams;
}
return request;
};
@@ -606,18 +659,55 @@ Remote.prototype.request_transaction_entry = function (hash) {
var request = new Request(this, 'rpc');
request.message.rpc_command = 'transaction_entry';
request.message.command = 'transaction_entry';
return request
.tx_hash(hash);
};
Remote.prototype.request_ripple_lines_get = function (accountID) {
// XXX Does this require the server to be trusted?
//assert(this.trusted);
var request = new Request(this, 'rpc');
request.message.command = 'ripple_lines_get';
// XXX Convert API call to JSON
request.message.params = [accountID];
return request;
};
Remote.prototype.request_wallet_accounts = function (key) {
// XXX Does this require the server to be trusted?
//assert(this.trusted);
var request = new Request(this, 'rpc');
request.message.command = 'wallet_accounts';
// XXX Convert API call to JSON
request.message.params = [key];
return request;
};
Remote.prototype.request_account_tx = function (accountID, minLedger, maxLedger) {
// XXX Does this require the server to be trusted?
//assert(this.trusted);
var request = new Request(this, 'rpc');
request.message.command = 'account_tx';
// XXX Convert API call to JSON
request.message.params = [accountID, minLedger, maxLedger];
return request;
};
// Submit a transaction.
Remote.prototype.submit = function (transaction) {
var self = this;
if (this.trace) console.log("remote: submit: %s", JSON.stringify(transaction.tx_json));
if (transaction.secret && !this.trusted)
{
transaction.emit('error', {
@@ -658,7 +748,7 @@ Remote.prototype.submit = function (transaction) {
else {
var submit_request = new Request(this, 'rpc');
submit_request.message.rpc_command = 'submit_json';
submit_request.message.command = 'submit_json';
submit_request.tx_json(transaction.tx_json);
submit_request.secret(transaction.secret);
@@ -685,7 +775,7 @@ Remote.prototype.submit = function (transaction) {
Remote.prototype._server_subscribe = function () {
var self = this;
this.request_subscribe()
this.request_subscribe([ 'ledger', 'server' ])
.on('success', function (message) {
self.stand_alone = !!message.stand_alone;
@@ -715,7 +805,7 @@ Remote.prototype.ledger_accept = function () {
{
var request = new Request(this, 'rpc');
request.message.rpc_command = 'ledger_accept';
request.message.command = 'ledger_accept';
request
.request();
@@ -766,7 +856,7 @@ Remote.prototype.set_account_seq = function (account, seq) {
var account = UInt160.json_rewrite(account);
if (!this.accounts[account]) this.accounts[account] = {};
this.accounts[account].seq = seq;
}
@@ -806,7 +896,7 @@ Remote.prototype.account_seq_cache = function (account, current) {
account_info.caching_seq_request = request;
}
return request
return request;
};
// Mark an account's root node as dirty.
@@ -861,6 +951,49 @@ Remote.prototype.request_ripple_balance = function (account, issuer, currency, c
});
}
Remote.prototype.request_unl_list = function () {
var request = new Request(this, 'rpc');
request.message.command = 'unl_list';
return request;
};
Remote.prototype.request_unl_add = function (addr, note) {
var request = new Request(this, 'rpc');
request.message.command = 'unl_add';
request.message.params = [addr, note];
return request;
};
Remote.prototype.request_unl_delete = function (publicKey) {
var request = new Request(this, 'rpc');
request.message.command = 'unl_delete';
request.message.params = [publicKey];
return request;
};
Remote.prototype.request_peers = function () {
var request = new Request(this, 'rpc');
request.message.command = 'peers';
return request;
};
Remote.prototype.request_connect = function (ip, port) {
var request = new Request(this, 'rpc');
request.message.command = 'connect';
request.message.params = [ip, port];
return request;
};
Remote.prototype.transaction = function () {
return new Transaction(this);
};