14 #include <boost/algorithm/string/classification.hpp> 15 #include <boost/algorithm/string/split.hpp> 16 #include <boost/signals2/signal.hpp> 21 #include <unordered_map> 25 static bool fRPCInWarmup
GUARDED_BY(g_rpc_warmup_mutex) =
true;
26 static std::string rpcWarmupStatus
GUARDED_BY(g_rpc_warmup_mutex) =
"RPC server started";
31 static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers
GUARDED_BY(g_deadline_timers_mutex);
43 std::list<RPCCommandExecutionInfo> active_commands
GUARDED_BY(mutex);
50 std::list<RPCCommandExecutionInfo>::iterator
it;
54 it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {
method,
GetTimeMicros()});
59 g_rpc_server_info.active_commands.erase(it);
83 std::set<intptr_t> setDone;
84 std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
86 for (
const auto& entry : mapCommands)
87 vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
88 sort(vCommands.begin(), vCommands.end());
94 for (
const std::pair<std::string, const CRPCCommand*>& command : vCommands)
97 std::string strMethod = pcmd->
name;
98 if ((strCommand !=
"" || pcmd->
category ==
"hidden") && strMethod != strCommand)
100 jreq.strMethod = strMethod;
104 if (setDone.insert(pcmd->
unique_id).second)
105 pcmd->
actor(jreq, unused_result,
true );
107 catch (
const std::exception& e)
110 std::string strHelp = std::string(e.what());
111 if (strCommand ==
"")
113 if (strHelp.find(
'\n') != std::string::npos)
114 strHelp = strHelp.substr(0, strHelp.find(
'\n'));
118 if (!category.empty())
121 strRet +=
"== " +
Capitalize(category) +
" ==\n";
124 strRet += strHelp +
"\n";
128 strRet =
strprintf(
"help: unknown command: %s\n", strCommand);
129 strRet = strRet.substr(0,strRet.size()-1);
136 "\nList all commands, or get help for a specified command.\n",
146 std::string strCommand;
147 if (jsonRequest.params.size() > 0)
148 strCommand = jsonRequest.params[0].
get_str();
157 static const std::string RESULT{
PACKAGE_NAME " stopping"};
173 if (jsonRequest.params[0].isNum()) {
184 "\nReturns the total uptime of the server.\n",
203 "\nReturns details of the RPC server.\n",
234 result.
pushKV(
"active_commands", active_commands);
238 result.
pushKV(
"logpath", log_path);
251 {
"control",
"help", &
help, {
"command"} },
252 {
"control",
"stop", &
stop, {
"wait"} },
253 {
"control",
"uptime", &
uptime, {} },
259 for (
const auto& c : vRPCCommands) {
260 appendCommand(c.name, &c);
268 mapCommands[
name].push_back(pcmd);
273 auto it = mapCommands.find(name);
274 if (
it != mapCommands.end()) {
275 auto new_end = std::remove(
it->second.begin(),
it->second.end(), pcmd);
276 if (
it->second.end() != new_end) {
277 it->second.erase(new_end,
it->second.end());
293 static std::once_flag g_rpc_interrupt_flag;
295 std::call_once(g_rpc_interrupt_flag, []() {
304 static std::once_flag g_rpc_stop_flag;
307 std::call_once(g_rpc_stop_flag, []() {
309 WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear());
327 LOCK(g_rpc_warmup_mutex);
328 rpcWarmupStatus = newStatus;
333 LOCK(g_rpc_warmup_mutex);
335 fRPCInWarmup =
false;
340 LOCK(g_rpc_warmup_mutex);
342 *outStatus = rpcWarmupStatus;
348 const std::vector<std::string> enabled_methods =
gArgs.
GetArgs(
"-deprecatedrpc");
350 return find(enabled_methods.begin(), enabled_methods.end(),
method) != enabled_methods.end();
367 catch (
const std::exception& e)
379 for (
unsigned int reqIdx = 0; reqIdx < vReq.
size(); reqIdx++)
382 return ret.
write() +
"\n";
397 std::unordered_map<std::string, const UniValue*> argsIn;
398 for (
size_t i=0; i<keys.size(); ++i) {
399 argsIn[keys[i]] = &values[i];
403 for (
const std::string &argNamePattern: argNames) {
404 std::vector<std::string> vargNames;
405 boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of(
"|"));
406 auto fr = argsIn.end();
407 for (
const std::string & argName : vargNames) {
408 fr = argsIn.find(argName);
409 if (fr != argsIn.end()) {
413 if (fr != argsIn.end()) {
414 for (
int i = 0; i < hole; ++i) {
428 if (!argsIn.empty()) {
439 LOCK(g_rpc_warmup_mutex);
446 if (
it != mapCommands.end()) {
448 for (
const auto& command :
it->second) {
449 if (
ExecuteCommand(*command, request, result, &command == &
it->second.back())) {
466 return command.
actor(request, result, last_handler);
469 catch (
const std::exception& e)
477 std::vector<std::string> commandList;
478 for (
const auto& i : mapCommands) commandList.emplace_back(i.first);
485 timerInterface = iface;
490 timerInterface = iface;
495 if (timerInterface == iface)
496 timerInterface =
nullptr;
499 void RPCRunLater(
const std::string&
name, std::function<
void()> func, int64_t nSeconds)
503 LOCK(g_deadline_timers_mutex);
504 deadlineTimers.erase(name);
505 LogPrint(
BCLog::RPC,
"queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->
Name());
506 deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->
NewTimer(func, nSeconds*1000)));
std::string Capitalize(std::string str)
Capitalizes the first character of the given string.
static const int SERIALIZE_TRANSACTION_NO_WITNESS
A flag that is ORed into the protocol version to designate that a transaction should be (un)serialize...
std::string help(const std::string &name, const JSONRPCRequest &helpreq) const
std::deque< CInv >::iterator it
const std::vector< UniValue > & getValues() const
static JSONRPCRequest transformNamedArguments(const JSONRPCRequest &in, const std::vector< std::string > &argNames)
Process named arguments into a vector of positional arguments, based on the passed-in specification f...
BCLog::Logger & LogInstance()
#define LogPrint(category,...)
bool IsRPCRunning()
Query whether RPC is running.
void SetRPCWarmupStatus(const std::string &newStatus)
Set the RPC warmup status.
static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
static bool fRPCInWarmup GUARDED_BY(g_rpc_warmup_mutex)
#define CHECK_NONFATAL(condition)
Throw a NonFatalCheckError when the condition evaluates to false.
static std::atomic< bool > g_rpc_running
void OnStopped(std::function< void()> slot)
bool removeCommand(const std::string &name, const CRPCCommand *pcmd)
const std::string & get_str() const
const std::vector< std::string > & getKeys() const
static const CRPCCommand vRPCCommands[]
void RPCRunLater(const std::string &name, std::function< void()> func, int64_t nSeconds)
Run func nSeconds from now.
std::vector< std::string > argNames
Invalid, missing or duplicate parameter.
static RPCServerInfo g_rpc_server_info
static Mutex g_deadline_timers_mutex
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
Unset factory function for timers.
void DeleteAuthCookie()
Delete RPC authentication cookie from disk.
static bool ExecuteCommand(const CRPCCommand &command, const JSONRPCRequest &request, UniValue &result, bool last_handler)
UniValue execute(const JSONRPCRequest &request) const
Execute a method.
boost::signals2::signal< void()> Stopped
void SetRPCWarmupFinished()
UniValue JSONRPCError(int code, const std::string &message)
bool push_back(const UniValue &val)
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
static RPCTimerInterface * timerInterface
boost::signals2::signal< void()> Started
std::string JSONRPCExecBatch(const JSONRPCRequest &jreq, const UniValue &vReq)
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
General application defined errors.
RPCCommandExecution(const std::string &method)
bool pushKV(const std::string &key, const UniValue &val)
bool IsDeprecatedRPCEnabled(const std::string &method)
static UniValue JSONRPCExecOne(JSONRPCRequest jreq, const UniValue &req)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
static struct CRPCSignals g_rpcSignals
Optional arg that is a named argument and has a default value of null.
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
Set the factory function for timer, but only, if unset.
virtual RPCTimerBase * NewTimer(std::function< void()> &func, int64_t millis)=0
Factory function for timers.
int64_t GetTimeMicros()
Returns the system time (not mockable)
void parse(const UniValue &valRequest)
void UninterruptibleSleep(const std::chrono::microseconds &n)
int RPCSerializationFlags()
void RpcInterruptionPoint()
Throw JSONRPCError if RPC is not running.
static RPCHelpMan getrpcinfo()
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
void RPCSetTimerInterface(RPCTimerInterface *iface)
Set the factory function for timers.
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
std::list< RPCCommandExecutionInfo >::iterator it
static Mutex g_rpc_warmup_mutex
bool RPCIsInWarmup(std::string *outStatus)
const UniValue NullUniValue
void StartShutdown()
Request shutdown of the application.
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
virtual const char * Name()=0
Implementation name.
void OnStarted(std::function< void()> slot)
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
int64_t GetTime()
Return system time (or mocked time, if set)
std::vector< std::string > listCommands() const
Returns a list of registered commands.
static RPCHelpMan uptime()