mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 05:25:55 +00:00
Refactored WSConnection and RPCHandler to have one layer of commands.
Evented RPC commands are now on the same level as all other RPC commands and are handled by the RPCHandler class.
This commit is contained in:
@@ -28,6 +28,16 @@ public:
|
|||||||
virtual ~InfoSub() { ; }
|
virtual ~InfoSub() { ; }
|
||||||
|
|
||||||
virtual void send(const Json::Value& jvObj) = 0;
|
virtual void send(const Json::Value& jvObj) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
boost::unordered_set<RippleAddress> mSubAccountInfo;
|
||||||
|
boost::unordered_set<RippleAddress> mSubAccountTransaction;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void insertSubAccountInfo(RippleAddress addr)
|
||||||
|
{
|
||||||
|
mSubAccountInfo.insert(addr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetworkOPs
|
class NetworkOPs
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ Json::Value RPCHandler::rpcError(int iError)
|
|||||||
{ rpcNO_ACCOUNT, "noAccount", "No such account." },
|
{ rpcNO_ACCOUNT, "noAccount", "No such account." },
|
||||||
{ rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." },
|
{ rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." },
|
||||||
{ rpcNO_CURRENT, "noCurrent", "Current 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_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." },
|
||||||
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
|
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
|
||||||
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
|
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
|
||||||
@@ -1298,7 +1299,7 @@ Json::Value RPCHandler::doLogRotate(const Json::Value& params)
|
|||||||
return Log::rotateLog();
|
return Log::rotateLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& params, int role)
|
Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& params, int role, InfoSub* sub)
|
||||||
{
|
{
|
||||||
cLog(lsTRACE) << "RPC:" << command;
|
cLog(lsTRACE) << "RPC:" << command;
|
||||||
cLog(lsTRACE) << "RPC params:" << params;
|
cLog(lsTRACE) << "RPC params:" << params;
|
||||||
@@ -1309,53 +1310,58 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
|
|||||||
int iMinParams;
|
int iMinParams;
|
||||||
int iMaxParams;
|
int iMaxParams;
|
||||||
bool mAdminRequired;
|
bool mAdminRequired;
|
||||||
|
bool mEvented;
|
||||||
unsigned int iOptions;
|
unsigned int iOptions;
|
||||||
} commandsA[] = {
|
} commandsA[] = {
|
||||||
|
// Request-response methods
|
||||||
{ "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true },
|
{ "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true },
|
||||||
{ "account_info", &RPCHandler::doAccountInfo, 1, 2, false, optCurrent },
|
{ "account_info", &RPCHandler::doAccountInfo, 1, 2, false, false, optCurrent },
|
||||||
{ "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, optNetwork },
|
{ "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, false, optNetwork },
|
||||||
{ "connect", &RPCHandler::doConnect, 1, 2, true },
|
{ "connect", &RPCHandler::doConnect, 1, 2, true },
|
||||||
{ "data_delete", &RPCHandler::doDataDelete, 1, 1, true },
|
{ "data_delete", &RPCHandler::doDataDelete, 1, 1, true },
|
||||||
{ "data_fetch", &RPCHandler::doDataFetch, 1, 1, true },
|
{ "data_fetch", &RPCHandler::doDataFetch, 1, 1, true },
|
||||||
{ "data_store", &RPCHandler::doDataStore, 2, 2, true },
|
{ "data_store", &RPCHandler::doDataStore, 2, 2, true },
|
||||||
{ "get_counts", &RPCHandler::doGetCounts, 0, 1, true },
|
{ "get_counts", &RPCHandler::doGetCounts, 0, 1, true },
|
||||||
{ "ledger", &RPCHandler::doLedger, 0, 2, false, optNetwork },
|
{ "ledger", &RPCHandler::doLedger, 0, 2, false, false, optNetwork },
|
||||||
{ "ledger_accept", &RPCHandler::doLedgerAccept, 0, 0, true, optCurrent },
|
{ "ledger_accept", &RPCHandler::doLedgerAccept, 0, 0, true, false, optCurrent },
|
||||||
{ "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, optClosed },
|
{ "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, false, optClosed },
|
||||||
{ "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, optCurrent },
|
{ "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, false, optCurrent },
|
||||||
{ "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, optCurrent },
|
{ "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, false, optCurrent },
|
||||||
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
|
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
|
||||||
{ "logrotate", &RPCHandler::doLogRotate, 0, 0, true },
|
{ "logrotate", &RPCHandler::doLogRotate, 0, 0, true },
|
||||||
{ "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, optCurrent },
|
{ "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, false, optCurrent },
|
||||||
{ "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, optCurrent },
|
{ "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, false, optCurrent },
|
||||||
{ "peers", &RPCHandler::doPeers, 0, 0, true },
|
{ "peers", &RPCHandler::doPeers, 0, 0, true },
|
||||||
{ "profile", &RPCHandler::doProfile, 1, 9, false, optCurrent },
|
{ "profile", &RPCHandler::doProfile, 1, 9, false, false, optCurrent },
|
||||||
{ "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, optCurrent },
|
{ "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, false, optCurrent },
|
||||||
{ "submit", &RPCHandler::doSubmit, 2, 2, false, optCurrent },
|
{ "submit", &RPCHandler::doSubmit, 2, 2, false, false, optCurrent },
|
||||||
{ "submit_json", &RPCHandler::doSubmitJson, -1, -1, false, optCurrent },
|
{ "submit_json", &RPCHandler::doSubmitJson, -1, -1, false, false, optCurrent },
|
||||||
{ "server_info", &RPCHandler::doServerInfo, 0, 0, true },
|
{ "server_info", &RPCHandler::doServerInfo, 0, 0, true },
|
||||||
{ "stop", &RPCHandler::doStop, 0, 0, true },
|
{ "stop", &RPCHandler::doStop, 0, 0, true },
|
||||||
{ "transaction_entry", &RPCHandler::doTransactionEntry, -1, -1, false, optCurrent },
|
{ "transaction_entry", &RPCHandler::doTransactionEntry, -1, -1, false, false, optCurrent },
|
||||||
{ "tx", &RPCHandler::doTx, 1, 1, true },
|
{ "tx", &RPCHandler::doTx, 1, 1, true },
|
||||||
{ "tx_history", &RPCHandler::doTxHistory, 1, 1, false, },
|
{ "tx_history", &RPCHandler::doTxHistory, 1, 1, false, },
|
||||||
|
|
||||||
{ "unl_add", &RPCHandler::doUnlAdd, 1, 2, true },
|
{ "unl_add", &RPCHandler::doUnlAdd, 1, 2, true },
|
||||||
{ "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true },
|
{ "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true },
|
||||||
{ "unl_list", &RPCHandler::doUnlList, 0, 0, true },
|
{ "unl_list", &RPCHandler::doUnlList, 0, 0, true },
|
||||||
{ "unl_load", &RPCHandler::doUnlLoad, 0, 0, true },
|
{ "unl_load", &RPCHandler::doUnlLoad, 0, 0, true },
|
||||||
{ "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true },
|
{ "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true },
|
||||||
{ "unl_reset", &RPCHandler::doUnlReset, 0, 0, true },
|
{ "unl_reset", &RPCHandler::doUnlReset, 0, 0, true },
|
||||||
{ "unl_score", &RPCHandler::doUnlScore, 0, 0, true },
|
{ "unl_score", &RPCHandler::doUnlScore, 0, 0, true },
|
||||||
|
|
||||||
{ "validation_create", &RPCHandler::doValidationCreate, 0, 1, false },
|
{ "validation_create", &RPCHandler::doValidationCreate, 0, 1, false },
|
||||||
{ "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false },
|
{ "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false },
|
||||||
|
|
||||||
{ "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, optCurrent },
|
{ "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, false, optCurrent },
|
||||||
{ "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, },
|
{ "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, },
|
||||||
{ "wallet_seed", &RPCHandler::doWalletSeed, 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);
|
int i = NUMBER(commandsA);
|
||||||
|
|
||||||
@@ -1370,6 +1376,10 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
|
|||||||
{
|
{
|
||||||
return rpcError(rpcNO_PERMISSION);
|
return rpcError(rpcNO_PERMISSION);
|
||||||
}
|
}
|
||||||
|
else if (commandsA[i].mEvented && sub == NULL)
|
||||||
|
{
|
||||||
|
return rpcError(rpcNO_EVENTS);
|
||||||
|
}
|
||||||
else if (commandsA[i].iMinParams >= 0
|
else if (commandsA[i].iMinParams >= 0
|
||||||
? commandsA[i].iMaxParams
|
? commandsA[i].iMaxParams
|
||||||
? (params.size() < commandsA[i].iMinParams
|
? (params.size() < commandsA[i].iMinParams
|
||||||
@@ -1396,6 +1406,11 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (sub != NULL)
|
||||||
|
{
|
||||||
|
isCurrent = sub;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (this->*(commandsA[i].dfpFunc))(params);
|
return (this->*(commandsA[i].dfpFunc))(params);
|
||||||
}
|
}
|
||||||
@@ -1933,4 +1948,191 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& jvRequest)
|
|||||||
return jvResult;
|
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(isCurrent, jvResult);
|
||||||
|
}else if(streamName=="ledger")
|
||||||
|
{
|
||||||
|
mNetOps->subLedger(isCurrent, jvResult);
|
||||||
|
}else if(streamName=="transactions")
|
||||||
|
{
|
||||||
|
mNetOps->subTransactions(isCurrent);
|
||||||
|
}else if(streamName=="rt_transactions")
|
||||||
|
{
|
||||||
|
mNetOps->subRTTransactions(isCurrent);
|
||||||
|
}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)
|
||||||
|
{
|
||||||
|
isCurrent->insertSubAccountInfo(naAccountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
mNetOps->subAccount(isCurrent, 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)
|
||||||
|
{
|
||||||
|
isCurrent->insertSubAccountInfo(naAccountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
mNetOps->subAccount(isCurrent, 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(isCurrent);
|
||||||
|
}else if(streamName=="ledger")
|
||||||
|
{
|
||||||
|
mNetOps->unsubLedger(isCurrent);
|
||||||
|
}else if(streamName=="transactions")
|
||||||
|
{
|
||||||
|
mNetOps->unsubTransactions(isCurrent);
|
||||||
|
}else if(streamName=="rt_transactions")
|
||||||
|
{
|
||||||
|
mNetOps->unsubRTTransactions(isCurrent);
|
||||||
|
}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)
|
||||||
|
{
|
||||||
|
isCurrent->insertSubAccountInfo(naAccountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
mNetOps->unsubAccount(isCurrent, 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)
|
||||||
|
{
|
||||||
|
isCurrent->insertSubAccountInfo(naAccountID);
|
||||||
|
}
|
||||||
|
|
||||||
|
mNetOps->unsubAccount(isCurrent, usnaAccoundIds,false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jvResult;
|
||||||
|
}
|
||||||
|
|
||||||
// vim:ts=4
|
// vim:ts=4
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ class NetworkOPs;
|
|||||||
|
|
||||||
class RPCHandler
|
class RPCHandler
|
||||||
{
|
{
|
||||||
NetworkOPs* mNetOps;
|
NetworkOPs* mNetOps;
|
||||||
|
InfoSub* isCurrent;
|
||||||
|
boost::mutex mLock;
|
||||||
|
|
||||||
typedef Json::Value (RPCHandler::*doFuncPtr)(const Json::Value ¶ms);
|
typedef Json::Value (RPCHandler::*doFuncPtr)(const Json::Value ¶ms);
|
||||||
enum {
|
enum {
|
||||||
@@ -15,6 +17,9 @@ class RPCHandler
|
|||||||
optClosed = 4+optNetwork, // Need closed ledger
|
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);
|
int getParamCount(const Json::Value& params);
|
||||||
bool extractString(std::string& param, const Json::Value& params, int index);
|
bool extractString(std::string& param, const Json::Value& params, int index);
|
||||||
|
|
||||||
@@ -84,8 +89,9 @@ class RPCHandler
|
|||||||
Json::Value doLedgerEntry(const Json::Value& params);
|
Json::Value doLedgerEntry(const Json::Value& params);
|
||||||
Json::Value doTransactionEntry(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:
|
public:
|
||||||
|
|
||||||
@@ -95,6 +101,7 @@ public:
|
|||||||
// Misc failure
|
// Misc failure
|
||||||
rpcLOAD_FAILED,
|
rpcLOAD_FAILED,
|
||||||
rpcNO_PERMISSION,
|
rpcNO_PERMISSION,
|
||||||
|
rpcNO_EVENTS,
|
||||||
rpcNOT_STANDALONE,
|
rpcNOT_STANDALONE,
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
@@ -152,7 +159,7 @@ public:
|
|||||||
|
|
||||||
RPCHandler(NetworkOPs* netOps);
|
RPCHandler(NetworkOPs* netOps);
|
||||||
|
|
||||||
Json::Value doCommand(const std::string& command, Json::Value& params,int role);
|
Json::Value doCommand(const std::string& command, Json::Value& params, int role, InfoSub* sub = NULL);
|
||||||
Json::Value rpcError(int iError);
|
Json::Value rpcError(int iError);
|
||||||
|
|
||||||
Json::Value handleJSONSubmit(const Json::Value& jvRequest);
|
Json::Value handleJSONSubmit(const Json::Value& jvRequest);
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ WSConnection::~WSConnection()
|
|||||||
mNetwork.unsubRTTransactions(this);
|
mNetwork.unsubRTTransactions(this);
|
||||||
mNetwork.unsubLedger(this);
|
mNetwork.unsubLedger(this);
|
||||||
mNetwork.unsubServer(this);
|
mNetwork.unsubServer(this);
|
||||||
mNetwork.unsubAccount(this, mSubAccountInfo,true);
|
mNetwork.unsubAccount(this, mSubAccountInfo, true);
|
||||||
mNetwork.unsubAccount(this, mSubAccountInfo,false);
|
mNetwork.unsubAccount(this, mSubAccountInfo, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSConnection::send(const Json::Value& jvObj)
|
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)
|
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"))
|
if (!jvRequest.isMember("command"))
|
||||||
{
|
{
|
||||||
Json::Value jvResult(Json::objectValue);
|
Json::Value jvResult(Json::objectValue);
|
||||||
@@ -56,22 +45,27 @@ Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
|
|||||||
return jvResult;
|
return jvResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string strCommand = jvRequest["command"].asString();
|
|
||||||
|
|
||||||
int i = NUMBER(commandsA);
|
|
||||||
|
|
||||||
while (i-- && strCommand != commandsA[i].pCommand)
|
|
||||||
;
|
|
||||||
|
|
||||||
Json::Value jvResult(Json::objectValue);
|
Json::Value jvResult(Json::objectValue);
|
||||||
|
|
||||||
if (i < 0)
|
// Regular RPC command
|
||||||
|
jvResult["result"] = theApp->getRPCHandler().doCommand(
|
||||||
|
jvRequest["command"].asString(),
|
||||||
|
jvRequest.isMember("params")
|
||||||
|
? jvRequest["params"]
|
||||||
|
: jvRequest,
|
||||||
|
mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN,
|
||||||
|
this);
|
||||||
|
|
||||||
|
// 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.
|
jvResult = jvResult["result"];
|
||||||
}
|
jvResult["status"] = "error";
|
||||||
else
|
jvResult["request"] = jvRequest;
|
||||||
{
|
} else {
|
||||||
(this->*(commandsA[i].dfpFunc))(jvResult, jvRequest);
|
jvResult["status"] = "success";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jvRequest.isMember("id"))
|
if (jvRequest.isMember("id"))
|
||||||
@@ -79,237 +73,9 @@ Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
|
|||||||
jvResult["id"] = jvRequest["id"];
|
jvResult["id"] = jvRequest["id"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jvResult.isMember("error"))
|
jvResult["type"] = "response";
|
||||||
{
|
|
||||||
jvResult["result"] = "error";
|
|
||||||
jvResult["request"] = jvRequest;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
jvResult["result"] = "success";
|
|
||||||
}
|
|
||||||
|
|
||||||
jvResult["type"] = "response";
|
|
||||||
|
|
||||||
return jvResult;
|
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
|
// vim:ts=4
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
typedef void (WSConnection::*doFuncPtr)(Json::Value& jvResult, Json::Value &jvRequest);
|
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;
|
WSServerHandler<websocketpp::WSDOOR_SERVER>* mHandler;
|
||||||
connection_ptr mConnection;
|
connection_ptr mConnection;
|
||||||
NetworkOPs& mNetwork;
|
NetworkOPs& mNetwork;
|
||||||
@@ -44,13 +40,6 @@ public:
|
|||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
Json::Value invokeCommand(Json::Value& jvRequest);
|
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);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -429,10 +429,10 @@ Remote.prototype._connect_message = function (ws, json) {
|
|||||||
if (!request) {
|
if (!request) {
|
||||||
unexpected = true;
|
unexpected = true;
|
||||||
}
|
}
|
||||||
else if ('success' === message.result) {
|
else if ('success' === message.status) {
|
||||||
if (this.trace) console.log("message: %s", json);
|
if (this.trace) console.log("message: %s", json);
|
||||||
|
|
||||||
request.emit('success', message);
|
request.emit('success', message.result);
|
||||||
}
|
}
|
||||||
else if (message.error) {
|
else if (message.error) {
|
||||||
if (this.trace) console.log("message: %s", json);
|
if (this.trace) console.log("message: %s", json);
|
||||||
@@ -515,7 +515,7 @@ Remote.prototype.request_ledger_hash = function () {
|
|||||||
|
|
||||||
var request = new Request(this, 'rpc');
|
var request = new Request(this, 'rpc');
|
||||||
|
|
||||||
request.message.rpc_command = 'ledger_closed';
|
request.message.command = 'ledger_closed';
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
};
|
};
|
||||||
@@ -525,7 +525,7 @@ Remote.prototype.request_ledger_hash = function () {
|
|||||||
Remote.prototype.request_ledger_current = function () {
|
Remote.prototype.request_ledger_current = function () {
|
||||||
var request = new Request(this, 'rpc');
|
var request = new Request(this, 'rpc');
|
||||||
|
|
||||||
request.message.rpc_command = 'ledger_current';
|
request.message.command = 'ledger_current';
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
};
|
};
|
||||||
@@ -540,7 +540,7 @@ Remote.prototype.request_ledger_entry = function (type) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var request = new Request(this, 'rpc');
|
var request = new Request(this, 'rpc');
|
||||||
|
|
||||||
request.message.rpc_command = 'ledger_entry';
|
request.message.command = 'ledger_entry';
|
||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@@ -593,10 +593,28 @@ Remote.prototype.request_ledger_entry = function (type) {
|
|||||||
return request;
|
return request;
|
||||||
};
|
};
|
||||||
|
|
||||||
Remote.prototype.request_subscribe = function () {
|
Remote.prototype.request_subscribe = function (streams) {
|
||||||
var request = new Request(this, 'subscribe');
|
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;
|
return request;
|
||||||
};
|
};
|
||||||
@@ -606,7 +624,7 @@ Remote.prototype.request_transaction_entry = function (hash) {
|
|||||||
|
|
||||||
var request = new Request(this, 'rpc');
|
var request = new Request(this, 'rpc');
|
||||||
|
|
||||||
request.message.rpc_command = 'transaction_entry';
|
request.message.command = 'transaction_entry';
|
||||||
|
|
||||||
return request
|
return request
|
||||||
.tx_hash(hash);
|
.tx_hash(hash);
|
||||||
@@ -658,7 +676,7 @@ Remote.prototype.submit = function (transaction) {
|
|||||||
else {
|
else {
|
||||||
var submit_request = new Request(this, 'rpc');
|
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.tx_json(transaction.tx_json);
|
||||||
submit_request.secret(transaction.secret);
|
submit_request.secret(transaction.secret);
|
||||||
@@ -685,7 +703,7 @@ Remote.prototype.submit = function (transaction) {
|
|||||||
Remote.prototype._server_subscribe = function () {
|
Remote.prototype._server_subscribe = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.request_subscribe()
|
this.request_subscribe([ 'ledger', 'server' ])
|
||||||
.on('success', function (message) {
|
.on('success', function (message) {
|
||||||
self.stand_alone = !!message.stand_alone;
|
self.stand_alone = !!message.stand_alone;
|
||||||
|
|
||||||
@@ -715,7 +733,7 @@ Remote.prototype.ledger_accept = function () {
|
|||||||
{
|
{
|
||||||
var request = new Request(this, 'rpc');
|
var request = new Request(this, 'rpc');
|
||||||
|
|
||||||
request.message.rpc_command = 'ledger_accept';
|
request.message.command = 'ledger_accept';
|
||||||
|
|
||||||
request
|
request
|
||||||
.request();
|
.request();
|
||||||
@@ -766,7 +784,7 @@ Remote.prototype.set_account_seq = function (account, seq) {
|
|||||||
var account = UInt160.json_rewrite(account);
|
var account = UInt160.json_rewrite(account);
|
||||||
|
|
||||||
if (!this.accounts[account]) this.accounts[account] = {};
|
if (!this.accounts[account]) this.accounts[account] = {};
|
||||||
|
|
||||||
this.accounts[account].seq = seq;
|
this.accounts[account].seq = seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,7 +824,7 @@ Remote.prototype.account_seq_cache = function (account, current) {
|
|||||||
account_info.caching_seq_request = request;
|
account_info.caching_seq_request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
return request
|
return request;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mark an account's root node as dirty.
|
// Mark an account's root node as dirty.
|
||||||
|
|||||||
Reference in New Issue
Block a user