mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-03 09:56:38 -05:00
cli: extract connection exception handler, -rpcwait logic
to ConnectAndCallRPC() to be callable for individual connections. This is needed for RPCs that need to be called and handled sequentially, rather than alone or in a batch. For example, when fetching the balances for each loaded wallet, -getinfo will call RPC listwallets, and then, depending on the result, RPC getbalances. It may be somewhat helpful to review this commit with `git show -w`.
This commit is contained in:
parent
5f19155e5b
commit
29f2cbdeb7
1 changed files with 62 additions and 49 deletions
|
@ -418,6 +418,40 @@ static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, co
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConnectAndCallRPC wraps CallRPC with -rpcwait and an exception handler.
|
||||||
|
*
|
||||||
|
* @param[in] rh Pointer to RequestHandler.
|
||||||
|
* @param[in] strMethod Reference to const string method to forward to CallRPC.
|
||||||
|
* @returns the RPC response as a UniValue object.
|
||||||
|
* @throws a CConnectionFailed std::runtime_error if connection failed or RPC server still in warmup.
|
||||||
|
*/
|
||||||
|
static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args)
|
||||||
|
{
|
||||||
|
UniValue response(UniValue::VOBJ);
|
||||||
|
// Execute and handle connection failures with -rpcwait.
|
||||||
|
const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
response = CallRPC(rh, strMethod, args);
|
||||||
|
if (fWait) {
|
||||||
|
const UniValue& error = find_value(response, "error");
|
||||||
|
if (!error.isNull() && error["code"].get_int() == RPC_IN_WARMUP) {
|
||||||
|
throw CConnectionFailed("server in warmup");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break; // Connection succeeded, no need to retry.
|
||||||
|
} catch (const CConnectionFailed&) {
|
||||||
|
if (fWait) {
|
||||||
|
UninterruptibleSleep(std::chrono::milliseconds{1000});
|
||||||
|
} else {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (fWait);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
static int CommandLineRPC(int argc, char *argv[])
|
static int CommandLineRPC(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
std::string strPrint;
|
std::string strPrint;
|
||||||
|
@ -485,62 +519,41 @@ static int CommandLineRPC(int argc, char *argv[])
|
||||||
method = args[0];
|
method = args[0];
|
||||||
args.erase(args.begin()); // Remove trailing method name from arguments vector
|
args.erase(args.begin()); // Remove trailing method name from arguments vector
|
||||||
}
|
}
|
||||||
|
const UniValue reply = ConnectAndCallRPC(rh.get(), method, args);
|
||||||
|
|
||||||
// Execute and handle connection failures with -rpcwait
|
// Parse reply
|
||||||
const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
|
UniValue result = find_value(reply, "result");
|
||||||
do {
|
const UniValue& error = find_value(reply, "error");
|
||||||
try {
|
if (!error.isNull()) {
|
||||||
const UniValue reply = CallRPC(rh.get(), method, args);
|
// Error
|
||||||
|
strPrint = "error: " + error.write();
|
||||||
|
nRet = abs(error["code"].get_int());
|
||||||
|
if (error.isObject()) {
|
||||||
|
const UniValue& errCode = find_value(error, "code");
|
||||||
|
const UniValue& errMsg = find_value(error, "message");
|
||||||
|
strPrint = errCode.isNull() ? "" : ("error code: " + errCode.getValStr() + "\n");
|
||||||
|
|
||||||
// Parse reply
|
if (errMsg.isStr()) {
|
||||||
const UniValue& result = find_value(reply, "result");
|
strPrint += ("error message:\n" + errMsg.get_str());
|
||||||
const UniValue& error = find_value(reply, "error");
|
}
|
||||||
|
if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
|
||||||
if (!error.isNull()) {
|
strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
|
||||||
// Error
|
|
||||||
int code = error["code"].get_int();
|
|
||||||
if (fWait && code == RPC_IN_WARMUP)
|
|
||||||
throw CConnectionFailed("server in warmup");
|
|
||||||
strPrint = "error: " + error.write();
|
|
||||||
nRet = abs(code);
|
|
||||||
if (error.isObject())
|
|
||||||
{
|
|
||||||
UniValue errCode = find_value(error, "code");
|
|
||||||
UniValue errMsg = find_value(error, "message");
|
|
||||||
strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
|
|
||||||
|
|
||||||
if (errMsg.isStr())
|
|
||||||
strPrint += "error message:\n"+errMsg.get_str();
|
|
||||||
|
|
||||||
if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
|
|
||||||
strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Result
|
|
||||||
if (result.isNull())
|
|
||||||
strPrint = "";
|
|
||||||
else if (result.isStr())
|
|
||||||
strPrint = result.get_str();
|
|
||||||
else
|
|
||||||
strPrint = result.write(2);
|
|
||||||
}
|
}
|
||||||
// Connection succeeded, no need to retry.
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
catch (const CConnectionFailed&) {
|
} else {
|
||||||
if (fWait)
|
// Result
|
||||||
UninterruptibleSleep(std::chrono::milliseconds{1000});
|
if (result.isNull()) {
|
||||||
else
|
strPrint = "";
|
||||||
throw;
|
} else if (result.isStr()) {
|
||||||
|
strPrint = result.get_str();
|
||||||
|
} else {
|
||||||
|
strPrint = result.write(2);
|
||||||
}
|
}
|
||||||
} while (fWait);
|
}
|
||||||
}
|
} catch (const std::exception& e) {
|
||||||
catch (const std::exception& e) {
|
|
||||||
strPrint = std::string("error: ") + e.what();
|
strPrint = std::string("error: ") + e.what();
|
||||||
nRet = EXIT_FAILURE;
|
nRet = EXIT_FAILURE;
|
||||||
}
|
} catch (...) {
|
||||||
catch (...) {
|
|
||||||
PrintExceptionContinue(nullptr, "CommandLineRPC()");
|
PrintExceptionContinue(nullptr, "CommandLineRPC()");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue