* 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. * @param[in] rpcwallet Reference to const optional string wallet name to forward to CallRPC. * @returns the RPC response as a UniValue object. * @throws a CConnectionFailed std::runtime_
| 1281 | * @throws a CConnectionFailed std::runtime_error if connection failed or RPC server still in warmup. |
| 1282 | */ |
| 1283 | static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const std::optional<std::string>& rpcwallet = {}) |
| 1284 | { |
| 1285 | UniValue response(UniValue::VOBJ); |
| 1286 | // Execute and handle connection failures with -rpcwait. |
| 1287 | const bool fWait = gArgs.GetBoolArg("-rpcwait", false); |
| 1288 | const int timeout = gArgs.GetIntArg("-rpcwaittimeout", DEFAULT_WAIT_CLIENT_TIMEOUT); |
| 1289 | const auto deadline{std::chrono::steady_clock::now() + 1s * timeout}; |
| 1290 | |
| 1291 | // check if we should use a special wallet endpoint |
| 1292 | std::string endpoint = "/"; |
| 1293 | if (rpcwallet) { |
| 1294 | endpoint = "/wallet/" + UrlEncode(*rpcwallet); |
| 1295 | } |
| 1296 | |
| 1297 | std::string username{gArgs.GetArg("-rpcuser", "")}; |
| 1298 | do { |
| 1299 | try { |
| 1300 | if (auto ipc_response{CallIPC(rh, strMethod, args, endpoint, username)}) { |
| 1301 | response = std::move(*ipc_response); |
| 1302 | } else { |
| 1303 | response = CallRPC(rh, strMethod, args, endpoint, username); |
| 1304 | } |
| 1305 | if (fWait) { |
| 1306 | const UniValue& error = response.find_value("error"); |
| 1307 | if (!error.isNull() && error["code"].getInt<int>() == RPC_IN_WARMUP) { |
| 1308 | throw CConnectionFailed("server in warmup"); |
| 1309 | } |
| 1310 | } |
| 1311 | break; // Connection succeeded, no need to retry. |
| 1312 | } catch (const CConnectionFailed& e) { |
| 1313 | if (fWait && (timeout <= 0 || std::chrono::steady_clock::now() < deadline)) { |
| 1314 | UninterruptibleSleep(1s); |
| 1315 | } else if (fWait) { |
| 1316 | throw CConnectionFailed(strprintf("timeout on transient error: %s", e.what())); |
| 1317 | } else { |
| 1318 | throw; |
| 1319 | } |
| 1320 | } |
| 1321 | } while (fWait); |
| 1322 | return response; |
| 1323 | } |
| 1324 | |
| 1325 | /** Parse UniValue result to update the message to print to std::cout. */ |
| 1326 | static void ParseResult(const UniValue& result, std::string& strPrint) |
no test coverage detected