Begin moving CLI parsing to CallRPC.

This commit is contained in:
Arthur Britto
2012-12-01 18:01:59 -08:00
parent d0e30b29d8
commit 8ffea0530a
2 changed files with 170 additions and 42 deletions

View File

@@ -13,11 +13,16 @@
#include "../json/value.h"
#include "../json/reader.h"
#include "CallRPC.h"
#include "RPC.h"
#include "Log.h"
#include "RPCErr.h"
#include "Config.h"
#include "BitcoinUtil.h"
#include "CallRPC.h"
SETUP_LOG();
static inline bool isSwitchChar(char c)
{
#ifdef __WXMSW__
@@ -46,73 +51,175 @@ std::string EncodeBase64(const std::string& s)
return result;
}
Json::Value RPCParser::parseAsIs(Json::Value jvReq, const Json::Value &params)
{
return jvReq;
}
// Convert a command plus args to a json request.
Json::Value RPCParser::parseCommand(Json::Value jvRequest)
{
std::string strCommand = jvRequest["method"].asString();
Json::Value jvParams = jvRequest["params"];
cLog(lsTRACE) << "RPC:" << strCommand;
cLog(lsTRACE) << "RPC params:" << jvParams;
static struct {
const char* pCommand;
parseFuncPtr pfpFunc;
int iMinParams;
int iMaxParams;
} commandsA[] = {
// Request-response methods
{ "accept_ledger", &RPCParser::parseAsIs, 0, 0 },
#if 0
{ "account_info", &RPCParser::doAccountInfo, 1, 2, false, false, optCurrent },
{ "account_tx", &RPCParser::doAccountTransactions, 2, 3, false, false, optNetwork },
{ "connect", &RPCParser::doConnect, 1, 2, true, false, optNone },
{ "data_delete", &RPCParser::doDataDelete, 1, 1, true, false, optNone },
{ "data_fetch", &RPCParser::doDataFetch, 1, 1, true, false, optNone },
{ "data_store", &RPCParser::doDataStore, 2, 2, true, false, optNone },
{ "get_counts", &RPCParser::doGetCounts, 0, 1, true, false, optNone },
{ "ledger", &RPCParser::doLedger, 0, 2, false, false, optNetwork },
{ "ledger_accept", &RPCParser::doLedgerAccept, 0, 0, true, false, optCurrent },
{ "ledger_closed", &RPCParser::doLedgerClosed, 0, 0, false, false, optClosed },
{ "ledger_current", &RPCParser::doLedgerCurrent, 0, 0, false, false, optCurrent },
{ "ledger_entry", &RPCParser::doLedgerEntry, -1, -1, false, false, optCurrent },
{ "ledger_header", &RPCParser::doLedgerHeader, -1, -1, false, false, optCurrent },
{ "log_level", &RPCParser::doLogLevel, 0, 2, true, false, optNone },
{ "logrotate", &RPCParser::doLogRotate, 0, 0, true, false, optNone },
{ "nickname_info", &RPCParser::doNicknameInfo, 1, 1, false, false, optCurrent },
{ "owner_info", &RPCParser::doOwnerInfo, 1, 2, false, false, optCurrent },
{ "peers", &RPCParser::doPeers, 0, 0, true, false, optNone },
{ "profile", &RPCParser::doProfile, 1, 9, false, false, optCurrent },
{ "ripple_lines_get", &RPCParser::doRippleLinesGet, 1, 2, false, false, optCurrent },
{ "ripple_path_find", &RPCParser::doRipplePathFind, -1, -1, false, false, optCurrent },
{ "submit", &RPCParser::doSubmit, 2, 2, false, false, optCurrent },
{ "submit_json", &RPCParser::doSubmitJson, -1, -1, false, false, optCurrent },
{ "server_info", &RPCParser::doServerInfo, 0, 0, true, false, optNone },
{ "stop", &RPCParser::doStop, 0, 0, true, false, optNone },
{ "transaction_entry", &RPCParser::doTransactionEntry, -1, -1, false, false, optCurrent },
{ "tx", &RPCParser::doTx, 1, 1, true, false, optNone },
{ "tx_history", &RPCParser::doTxHistory, 1, 1, false, false, optNone },
{ "unl_add", &RPCParser::doUnlAdd, 1, 2, true, false, optNone },
{ "unl_delete", &RPCParser::doUnlDelete, 1, 1, true, false, optNone },
{ "unl_list", &RPCParser::doUnlList, 0, 0, true, false, optNone },
{ "unl_load", &RPCParser::doUnlLoad, 0, 0, true, false, optNone },
{ "unl_network", &RPCParser::doUnlNetwork, 0, 0, true, false, optNone },
{ "unl_reset", &RPCParser::doUnlReset, 0, 0, true, false, optNone },
{ "unl_score", &RPCParser::doUnlScore, 0, 0, true, false, optNone },
{ "validation_create", &RPCParser::doValidationCreate, 0, 1, false, false, optNone },
{ "validation_seed", &RPCParser::doValidationSeed, 0, 1, false, false, optNone },
{ "wallet_accounts", &RPCParser::doWalletAccounts, 1, 1, false, false, optCurrent },
{ "wallet_propose", &RPCParser::doWalletPropose, 0, 1, false, false, optNone },
{ "wallet_seed", &RPCParser::doWalletSeed, 0, 1, false, false, optNone },
{ "login", &RPCParser::doLogin, 2, 2, true, false, optNone },
// Evented methods
{ "subscribe", &RPCParser::doSubscribe, -1, -1, false, true, optNone },
{ "unsubscribe", &RPCParser::doUnsubscribe, -1, -1, false, true, optNone },
#endif
};
int i = NUMBER(commandsA);
while (i-- && strCommand != commandsA[i].pCommand)
;
if (i < 0)
{
return rpcError(rpcBAD_SYNTAX, jvRequest);
}
else if (commandsA[i].iMinParams >= 0
? commandsA[i].iMaxParams
? (jvParams.size() < commandsA[i].iMinParams
|| (commandsA[i].iMaxParams >= 0 && jvParams.size() > commandsA[i].iMaxParams))
: false
: jvParams.isArray())
{
return rpcError(rpcBAD_SYNTAX, jvRequest);
}
return (this->*(commandsA[i].pfpFunc))(jvRequest, jvParams);
}
int commandLineRPC(const std::vector<std::string>& vCmd)
{
std::string strPrint;
int nRet = 0;
Json::Value jvOutput;
int nRet = 0;
Json::Value jvRequest(Json::objectValue);
try
{
if (vCmd.empty()) return 1;
RPCParser rpParser;
Json::Value jvCliParams(Json::arrayValue);
std::string strMethod = vCmd[0];
if (vCmd.empty()) return 1; // 1 = print usage.
jvRequest["method"] = vCmd[0];
// Parameters default to strings
Json::Value params(Json::arrayValue);
for (int i = 1; i != vCmd.size(); i++)
params.append(vCmd[i]);
jvCliParams.append(vCmd[i]);
// Execute
Json::Value reply = callRPC(strMethod, params);
jvRequest["params"] = jvCliParams;
// Parse reply
Json::Value result = reply.get("result", Json::Value());
Json::Value error = reply.get("error", Json::Value());
jvRequest = rpParser.parseCommand(jvRequest);
if (result.isString() && (result.asString() == "unknown command"))
nRet=1;
// std::cerr << "Request: " << jvRequest << std::endl;
if (!error.isNull())
{ // Error
strPrint = "error: " + error.toStyledString();
int code = error["code"].asInt();
nRet = abs(code);
}
else
{ // Result
if (result.isNull())
strPrint = "";
else if (result.isString())
strPrint = result.asString();
else
strPrint = result.toStyledString();
Json::Value jvParams(Json::arrayValue);
jvParams.append(jvRequest);
Json::Value jvResult;
jvResult = jvRequest.isMember("error")
? jvRequest // Parse failed, return error.
: callRPC(jvRequest["method"].asString(), jvParams); // Parsed, execute.
if (jvResult.isMember("error"))
{
nRet = jvResult.isMember("error_code")
? lexical_cast_s<int>(jvResult["error_code"].asString())
: 1;
}
jvOutput = jvResult;
}
catch (std::exception& e)
{
strPrint = std::string("error: ") + e.what();
nRet = 87;
jvRequest["error_what"] = e.what();
jvOutput = rpcError(rpcINTERNAL, jvRequest);
nRet = rpcINTERNAL;
}
catch (...)
{
std::cout << "Exception CommandLineRPC()" << std::endl;
jvRequest["error_what"] = "exception";
jvOutput = rpcError(rpcINTERNAL, jvRequest);
nRet = rpcINTERNAL;
}
if (strPrint != "")
{
std::cout << strPrint << std::endl;
}
std::cout << jvOutput.toStyledString();
return nRet;
}
Json::Value callRPC(const std::string& strMethod, const Json::Value& params)
{
if (theConfig.RPC_USER.empty() && theConfig.RPC_PASSWORD.empty())
throw std::runtime_error("You must set rpcpassword=<password> in the configuration file"
throw std::runtime_error("You must set rpcpassword=<password> in the configuration file. "
"If the file does not exist, create it with owner-readable-only file permissions.");
// Connect to localhost
std::cout << "Connecting to: " << theConfig.RPC_IP << ":" << theConfig.RPC_PORT << std::endl;
if (!theConfig.QUIET)
std::cerr << "Connecting to: " << theConfig.RPC_IP << ":" << theConfig.RPC_PORT << std::endl;
boost::asio::ip::tcp::endpoint
endpoint(boost::asio::ip::address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT);
@@ -128,11 +235,11 @@ Json::Value callRPC(const std::string& strMethod, const Json::Value& params)
// Send request
std::string strRequest = JSONRPCRequest(strMethod, params, Json::Value(1));
std::cout << "send request " << strMethod << " : " << strRequest << std::endl;
cLog(lsDEBUG) << "send request " << strMethod << " : " << strRequest << std::endl;
std::string strPost = createHTTPPost(strRequest, mapRequestHeaders);
stream << strPost << std::flush;
// std::cout << "post " << strPost << std::endl;
// std::cerr << "post " << strPost << std::endl;
// Receive reply
std::map<std::string, std::string> mapHeaders;
@@ -146,11 +253,14 @@ Json::Value callRPC(const std::string& strMethod, const Json::Value& params)
throw std::runtime_error("no response from server");
// Parse reply
std::cout << "RPC reply: " << strReply << std::endl;
cLog(lsDEBUG) << "RPC reply: " << strReply << std::endl;
Json::Reader reader;
Json::Value valReply;
if (!reader.parse(strReply, valReply))
throw std::runtime_error("couldn't parse reply from server");
if (valReply.isNull())
throw std::runtime_error("expected reply to have result, error and id properties");