Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/server.cpp
Show All 29 Lines | |||||
static bool fRPCInWarmup = true; | static bool fRPCInWarmup = true; | ||||
static std::string rpcWarmupStatus("RPC server started"); | static std::string rpcWarmupStatus("RPC server started"); | ||||
static CCriticalSection cs_rpcWarmup; | static CCriticalSection cs_rpcWarmup; | ||||
/* Timer-creating functions */ | /* Timer-creating functions */ | ||||
static RPCTimerInterface *timerInterface = nullptr; | static RPCTimerInterface *timerInterface = nullptr; | ||||
/* Map of name to timer. */ | /* Map of name to timer. */ | ||||
static std::map<std::string, std::unique_ptr<RPCTimerBase>> deadlineTimers; | static std::map<std::string, std::unique_ptr<RPCTimerBase>> deadlineTimers; | ||||
struct RPCCommandExecutionInfo { | |||||
std::string method; | |||||
int64_t start; | |||||
}; | |||||
struct RPCServerInfo { | |||||
Mutex mutex; | |||||
std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex); | |||||
}; | |||||
static RPCServerInfo g_rpc_server_info; | |||||
struct RPCCommandExecution { | |||||
std::list<RPCCommandExecutionInfo>::iterator it; | |||||
explicit RPCCommandExecution(const std::string &method) { | |||||
LOCK(g_rpc_server_info.mutex); | |||||
it = g_rpc_server_info.active_commands.insert( | |||||
g_rpc_server_info.active_commands.cend(), | |||||
{method, GetTimeMicros()}); | |||||
} | |||||
~RPCCommandExecution() { | |||||
LOCK(g_rpc_server_info.mutex); | |||||
g_rpc_server_info.active_commands.erase(it); | |||||
} | |||||
}; | |||||
UniValue RPCServer::ExecuteCommand(Config &config, | UniValue RPCServer::ExecuteCommand(Config &config, | ||||
const JSONRPCRequest &request) const { | const JSONRPCRequest &request) const { | ||||
// Return immediately if in warmup | // Return immediately if in warmup | ||||
// This is retained from the old RPC implementation because a lot of state | // This is retained from the old RPC implementation because a lot of state | ||||
// is set during warmup that RPC commands may depend on. This can be | // is set during warmup that RPC commands may depend on. This can be | ||||
// safely removed once global variable usage has been eliminated. | // safely removed once global variable usage has been eliminated. | ||||
{ | { | ||||
LOCK(cs_rpcWarmup); | LOCK(cs_rpcWarmup); | ||||
Show All 24 Lines | if (command != nullptr) { | ||||
commands.getWriteView()->insert( | commands.getWriteView()->insert( | ||||
std::make_pair(commandName, std::move(command))); | std::make_pair(commandName, std::move(command))); | ||||
} | } | ||||
} | } | ||||
static struct CRPCSignals { | static struct CRPCSignals { | ||||
boost::signals2::signal<void()> Started; | boost::signals2::signal<void()> Started; | ||||
boost::signals2::signal<void()> Stopped; | boost::signals2::signal<void()> Stopped; | ||||
boost::signals2::signal<void(const ContextFreeRPCCommand &)> PreCommand; | |||||
} g_rpcSignals; | } g_rpcSignals; | ||||
void RPCServerSignals::OnStarted(std::function<void()> slot) { | void RPCServerSignals::OnStarted(std::function<void()> slot) { | ||||
g_rpcSignals.Started.connect(slot); | g_rpcSignals.Started.connect(slot); | ||||
} | } | ||||
void RPCServerSignals::OnStopped(std::function<void()> slot) { | void RPCServerSignals::OnStopped(std::function<void()> slot) { | ||||
g_rpcSignals.Stopped.connect(slot); | g_rpcSignals.Stopped.connect(slot); | ||||
▲ Show 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | if (jsonRequest.fHelp || jsonRequest.params.size() > 1) { | ||||
"\nExamples:\n" + | "\nExamples:\n" + | ||||
HelpExampleCli("uptime", "") + | HelpExampleCli("uptime", "") + | ||||
HelpExampleRpc("uptime", "")); | HelpExampleRpc("uptime", "")); | ||||
} | } | ||||
return GetTime() - GetStartupTime(); | return GetTime() - GetStartupTime(); | ||||
} | } | ||||
static UniValue getrpcinfo(const Config &config, | |||||
const JSONRPCRequest &request) { | |||||
if (request.fHelp || request.params.size() > 0) { | |||||
throw std::runtime_error("getrpcinfo\n" | |||||
"\nReturns details of the RPC server.\n"); | |||||
} | |||||
LOCK(g_rpc_server_info.mutex); | |||||
UniValue active_commands(UniValue::VARR); | |||||
for (const RPCCommandExecutionInfo &info : | |||||
g_rpc_server_info.active_commands) { | |||||
UniValue entry(UniValue::VOBJ); | |||||
entry.pushKV("method", info.method); | |||||
entry.pushKV("duration", GetTimeMicros() - info.start); | |||||
active_commands.push_back(entry); | |||||
} | |||||
UniValue result(UniValue::VOBJ); | |||||
result.pushKV("active_commands", active_commands); | |||||
return result; | |||||
} | |||||
/** | /** | ||||
* Call Table | * Call Table | ||||
*/ | */ | ||||
// clang-format off | // clang-format off | ||||
static const ContextFreeRPCCommand vRPCCommands[] = { | static const ContextFreeRPCCommand vRPCCommands[] = { | ||||
// category name actor (function) argNames | // category name actor (function) argNames | ||||
// ------------------- ------------------------ ---------------------- ---------- | // ------------------- ------------------------ ---------------------- ---------- | ||||
/* Overall control/query calls */ | /* Overall control/query calls */ | ||||
{ "control", "getrpcinfo", getrpcinfo, {} }, | |||||
{ "control", "help", help, {"command"} }, | { "control", "help", help, {"command"} }, | ||||
{ "control", "stop", stop, {"wait"} }, | { "control", "stop", stop, {"wait"} }, | ||||
{ "control", "uptime", uptime, {} }, | { "control", "uptime", uptime, {} }, | ||||
}; | }; | ||||
// clang-format on | // clang-format on | ||||
CRPCTable::CRPCTable() { | CRPCTable::CRPCTable() { | ||||
unsigned int vcidx; | unsigned int vcidx; | ||||
▲ Show 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | UniValue CRPCTable::execute(Config &config, | ||||
// Check if legacy RPC method is valid. | // Check if legacy RPC method is valid. | ||||
// See RPCServer::ExecuteCommand for context-sensitive RPC commands. | // See RPCServer::ExecuteCommand for context-sensitive RPC commands. | ||||
const ContextFreeRPCCommand *pcmd = tableRPC[request.strMethod]; | const ContextFreeRPCCommand *pcmd = tableRPC[request.strMethod]; | ||||
if (!pcmd) { | if (!pcmd) { | ||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); | ||||
} | } | ||||
g_rpcSignals.PreCommand(*pcmd); | |||||
try { | try { | ||||
RPCCommandExecution execution(request.strMethod); | |||||
// Execute, convert arguments to array if necessary | // Execute, convert arguments to array if necessary | ||||
if (request.params.isObject()) { | if (request.params.isObject()) { | ||||
return pcmd->call(config, | return pcmd->call(config, | ||||
transformNamedArguments(request, pcmd->argNames)); | transformNamedArguments(request, pcmd->argNames)); | ||||
} else { | } else { | ||||
return pcmd->call(config, request); | return pcmd->call(config, request); | ||||
} | } | ||||
} catch (const std::exception &e) { | } catch (const std::exception &e) { | ||||
▲ Show 20 Lines • Show All 61 Lines • Show Last 20 Lines |