mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 13:35:54 +00:00
Refactor away RPCHandler::doRpcCommand
This commit is contained in:
committed by
Vinnie Falco
parent
fc9a23d6d4
commit
c72db5fa5f
@@ -68,10 +68,12 @@ void startServer ()
|
|||||||
if (!getConfig ().QUIET)
|
if (!getConfig ().QUIET)
|
||||||
std::cerr << "Startup RPC: " << jvCommand << std::endl;
|
std::cerr << "Startup RPC: " << jvCommand << std::endl;
|
||||||
|
|
||||||
RPCHandler rhHandler (getApp().getOPs ());
|
|
||||||
|
|
||||||
Resource::Charge loadType = Resource::feeReferenceRPC;
|
Resource::Charge loadType = Resource::feeReferenceRPC;
|
||||||
Json::Value jvResult = rhHandler.doCommand (jvCommand, Role::ADMIN, loadType);
|
RPC::Context context {
|
||||||
|
jvCommand, loadType, getApp().getOPs (), Role::ADMIN};
|
||||||
|
|
||||||
|
Json::Value jvResult;
|
||||||
|
RPC::doCommand (context, jvResult);
|
||||||
|
|
||||||
if (!getConfig ().QUIET)
|
if (!getConfig ().QUIET)
|
||||||
std::cerr << "Result: " << jvResult << std::endl;
|
std::cerr << "Result: " << jvResult << std::endl;
|
||||||
|
|||||||
@@ -159,8 +159,6 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Resource::Charge loadType = Resource::feeReferenceRPC;
|
Resource::Charge loadType = Resource::feeReferenceRPC;
|
||||||
RPCHandler mRPCHandler (m_netOPs, std::dynamic_pointer_cast<InfoSub> (
|
|
||||||
this->shared_from_this ()));
|
|
||||||
Json::Value jvResult (Json::objectValue);
|
Json::Value jvResult (Json::objectValue);
|
||||||
|
|
||||||
Role const role = port_.allow_admin ? adminRole (port_, jvRequest,
|
Role const role = port_.allow_admin ? adminRole (port_, jvRequest,
|
||||||
@@ -172,8 +170,10 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
jvResult[jss::result] = mRPCHandler.doCommand (
|
RPC::Context context {
|
||||||
jvRequest, role, loadType);
|
jvRequest, loadType, m_netOPs, role,
|
||||||
|
std::dynamic_pointer_cast<InfoSub> (this->shared_from_this ())};
|
||||||
|
RPC::doCommand (context, jvResult[jss::result]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getConsumer().charge (loadType);
|
getConsumer().charge (loadType);
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
Json::Value const& logRPCError (Json::Value const& json);
|
|
||||||
|
|
||||||
// VFALCO NOTE these are deprecated
|
// VFALCO NOTE these are deprecated
|
||||||
bool isRpcError (Json::Value jvResult);
|
bool isRpcError (Json::Value jvResult);
|
||||||
Json::Value rpcError (int iError,
|
Json::Value rpcError (int iError,
|
||||||
|
|||||||
@@ -34,17 +34,4 @@ bool isRpcError (Json::Value jvResult)
|
|||||||
return jvResult.isObject () && jvResult.isMember ("error");
|
return jvResult.isObject () && jvResult.isMember ("error");
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value const& logRPCError (Json::Value const& json)
|
|
||||||
{
|
|
||||||
if (RPC::contains_error (json))
|
|
||||||
{
|
|
||||||
WriteLog (lsDEBUG, RPCErr) <<
|
|
||||||
"rpcError: " << json ["error"] <<
|
|
||||||
": " << json ["error_message"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
|
|||||||
@@ -23,40 +23,22 @@
|
|||||||
#include <ripple/server/Role.h>
|
#include <ripple/server/Role.h>
|
||||||
#include <ripple/core/Config.h>
|
#include <ripple/core/Config.h>
|
||||||
#include <ripple/net/InfoSub.h>
|
#include <ripple/net/InfoSub.h>
|
||||||
#include <ripple/rpc/Yield.h>
|
#include <ripple/rpc/impl/Context.h>
|
||||||
|
#include <ripple/rpc/Status.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
namespace RPC {
|
||||||
|
|
||||||
class NetworkOPs;
|
/** Execute an RPC command and store the results in a Json::Value. */
|
||||||
|
Status doCommand (RPC::Context&, Json::Value&);
|
||||||
|
|
||||||
class RPCHandler
|
/** Execute an RPC command and store the results in an std::string. */
|
||||||
{
|
void executeRPC (RPC::Context&, std::string&);
|
||||||
public:
|
|
||||||
explicit RPCHandler (
|
|
||||||
NetworkOPs& netOps, InfoSub::pointer infoSub = nullptr);
|
|
||||||
|
|
||||||
using Yield = RPC::Yield;
|
/** Temporary flag to enable RPCs. */
|
||||||
|
auto const streamingRPC = false;
|
||||||
Json::Value doCommand (
|
|
||||||
Json::Value const& request,
|
|
||||||
Role role,
|
|
||||||
Resource::Charge& loadType,
|
|
||||||
Yield yield = {});
|
|
||||||
|
|
||||||
Json::Value doRpcCommand (
|
|
||||||
std::string const& command,
|
|
||||||
Json::Value const& params,
|
|
||||||
Role role,
|
|
||||||
Resource::Charge& loadType,
|
|
||||||
Yield yield = {});
|
|
||||||
|
|
||||||
private:
|
|
||||||
NetworkOPs& netOps_;
|
|
||||||
InfoSub::pointer infoSub_;
|
|
||||||
|
|
||||||
Role role_ = Role::FORBID;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
} // RPC
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -61,14 +61,16 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status (error_code_i e, std::string const& s)
|
||||||
|
: type_ (Type::error_code_i), code_ (e), messages_ ({s})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns a representation of the integer status Code as a string.
|
/* Returns a representation of the integer status Code as a string.
|
||||||
If the Status is OK, the result is an empty string.
|
If the Status is OK, the result is an empty string.
|
||||||
*/
|
*/
|
||||||
std::string codeString () const;
|
std::string codeString () const;
|
||||||
|
|
||||||
/** Fill a Json::Value. If the Status is OK, fillJson has no effect. */
|
|
||||||
void fillJson(Json::Value&);
|
|
||||||
|
|
||||||
/** Returns true if the Status is *not* OK. */
|
/** Returns true if the Status is *not* OK. */
|
||||||
operator bool() const
|
operator bool() const
|
||||||
{
|
{
|
||||||
@@ -97,16 +99,40 @@ public:
|
|||||||
return error_code_i (code_);
|
return error_code_i (code_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Apply the Status to a JsonObject
|
||||||
|
*/
|
||||||
|
template <class Object>
|
||||||
|
void inject (Object& object)
|
||||||
|
{
|
||||||
|
if (auto ec = toErrorCode())
|
||||||
|
{
|
||||||
|
if (messages_.empty())
|
||||||
|
inject_error (ec, object);
|
||||||
|
else
|
||||||
|
inject_error (ec, message(), object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Strings const& messages() const
|
Strings const& messages() const
|
||||||
{
|
{
|
||||||
return messages_;
|
return messages_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return the first message, if any. */
|
||||||
|
std::string message() const;
|
||||||
|
|
||||||
Type type() const
|
Type type() const
|
||||||
{
|
{
|
||||||
return type_;
|
return type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string toString() const;
|
||||||
|
|
||||||
|
/** Fill a Json::Value with an RPC 2.0 response.
|
||||||
|
If the Status is OK, fillJson has no effect.
|
||||||
|
Not currently used. */
|
||||||
|
void fillJson(Json::Value&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type type_ = Type::none;
|
Type type_ = Type::none;
|
||||||
Code code_ = OK;
|
Code code_ = OK;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <ripple/app/ledger/LedgerToJson.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <ripple/app/ledger/LedgerToJson.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <ripple/app/paths/AccountCurrencies.h>
|
#include <ripple/app/paths/AccountCurrencies.h>
|
||||||
#include <ripple/app/paths/FindPaths.h>
|
#include <ripple/app/paths/FindPaths.h>
|
||||||
|
#include <ripple/core/LoadFeeTrack.h>
|
||||||
#include <ripple/protocol/STParsedJSON.h>
|
#include <ripple/protocol/STParsedJSON.h>
|
||||||
#include <ripple/rpc/impl/LegacyPathFind.h>
|
#include <ripple/rpc/impl/LegacyPathFind.h>
|
||||||
#include <ripple/server/Role.h>
|
#include <ripple/server/Role.h>
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ struct Context
|
|||||||
Json::Value params;
|
Json::Value params;
|
||||||
Resource::Charge& loadType;
|
Resource::Charge& loadType;
|
||||||
NetworkOPs& netOps;
|
NetworkOPs& netOps;
|
||||||
InfoSub::pointer infoSub;
|
|
||||||
Role role;
|
Role role;
|
||||||
|
InfoSub::pointer infoSub;
|
||||||
RPC::Yield yield;
|
RPC::Yield yield;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define RIPPLED_RIPPLE_BASICS_TYPES_JSONWRITER_H
|
#define RIPPLED_RIPPLE_BASICS_TYPES_JSONWRITER_H
|
||||||
|
|
||||||
#include <ripple/basics/ToString.h>
|
#include <ripple/basics/ToString.h>
|
||||||
|
#include <ripple/rpc/ErrorCodes.h>
|
||||||
#include <ripple/rpc/Output.h>
|
#include <ripple/rpc/Output.h>
|
||||||
#include <ripple/rpc/ErrorCodes.h>
|
#include <ripple/rpc/ErrorCodes.h>
|
||||||
|
|
||||||
|
|||||||
@@ -25,137 +25,226 @@
|
|||||||
#include <ripple/rpc/impl/Tuning.h>
|
#include <ripple/rpc/impl/Tuning.h>
|
||||||
#include <ripple/rpc/impl/Context.h>
|
#include <ripple/rpc/impl/Context.h>
|
||||||
#include <ripple/rpc/impl/Handler.h>
|
#include <ripple/rpc/impl/Handler.h>
|
||||||
|
#include <ripple/rpc/impl/WriteJson.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
namespace RPC {
|
||||||
|
|
||||||
RPCHandler::RPCHandler (NetworkOPs& netOps, InfoSub::pointer infoSub)
|
namespace {
|
||||||
: netOps_ (netOps)
|
|
||||||
, infoSub_ (infoSub)
|
/**
|
||||||
|
This code is called from both the HTTP RPC handler and Websockets.
|
||||||
|
|
||||||
|
The form of the Json returned is somewhat different between the two services.
|
||||||
|
|
||||||
|
HTML:
|
||||||
|
Success:
|
||||||
|
{
|
||||||
|
"result" : {
|
||||||
|
"ledger" : {
|
||||||
|
"accepted" : false,
|
||||||
|
"transaction_hash" : "..."
|
||||||
|
},
|
||||||
|
"ledger_index" : 10300865,
|
||||||
|
"validated" : false,
|
||||||
|
"status" : "success" # Status is inside the result.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Failure:
|
||||||
|
{
|
||||||
|
"result" : {
|
||||||
|
"error" : "noNetwork",
|
||||||
|
"error_code" : 16,
|
||||||
|
"error_message" : "Not synced to Ripple network.",
|
||||||
|
"request" : {
|
||||||
|
"command" : "ledger",
|
||||||
|
"ledger_index" : 10300865
|
||||||
|
},
|
||||||
|
"status" : "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Websocket:
|
||||||
|
Success:
|
||||||
|
{
|
||||||
|
"result" : {
|
||||||
|
"ledger" : {
|
||||||
|
"accepted" : false,
|
||||||
|
"transaction_hash" : "..."
|
||||||
|
},
|
||||||
|
"ledger_index" : 10300865,
|
||||||
|
"validated" : false
|
||||||
|
}
|
||||||
|
"type": "response",
|
||||||
|
"status": "success", # Status is OUTside the result!
|
||||||
|
"id": "client's ID", # Optional
|
||||||
|
"warning": 3.14 # Optional
|
||||||
|
}
|
||||||
|
|
||||||
|
Failure:
|
||||||
|
{
|
||||||
|
"error" : "noNetwork",
|
||||||
|
"error_code" : 16,
|
||||||
|
"error_message" : "Not synced to Ripple network.",
|
||||||
|
"request" : {
|
||||||
|
"command" : "ledger",
|
||||||
|
"ledger_index" : 10300865
|
||||||
|
},
|
||||||
|
"type": "response",
|
||||||
|
"status" : "error",
|
||||||
|
"id": "client's ID" # Optional
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
error_code_i fillHandler (Context& context,
|
||||||
|
boost::optional<Handler const&>& result)
|
||||||
{
|
{
|
||||||
}
|
if (context.role != Role::ADMIN)
|
||||||
|
|
||||||
// Provide the JSON-RPC "result" value.
|
|
||||||
//
|
|
||||||
// JSON-RPC provides a method and an array of params. JSON-RPC is used as a
|
|
||||||
// transport for a command and a request object. The command is the method. The
|
|
||||||
// request object is supplied as the first element of the params.
|
|
||||||
Json::Value RPCHandler::doRpcCommand (
|
|
||||||
const std::string& strMethod,
|
|
||||||
Json::Value const& jvParams,
|
|
||||||
Role role,
|
|
||||||
Resource::Charge& loadType,
|
|
||||||
Yield yield)
|
|
||||||
{
|
|
||||||
WriteLog (lsTRACE, RPCHandler)
|
|
||||||
<< "doRpcCommand:" << strMethod << ":" << jvParams;
|
|
||||||
|
|
||||||
if (!jvParams.isArray () || jvParams.size () > 1)
|
|
||||||
return logRPCError (rpcError (rpcINVALID_PARAMS));
|
|
||||||
|
|
||||||
Json::Value params = jvParams.size () ? jvParams[0u]
|
|
||||||
: Json::Value (Json::objectValue);
|
|
||||||
|
|
||||||
if (!params.isObject ())
|
|
||||||
return logRPCError (rpcError (rpcINVALID_PARAMS));
|
|
||||||
|
|
||||||
// Provide the JSON-RPC method as the field "command" in the request.
|
|
||||||
params[jss::command] = strMethod;
|
|
||||||
|
|
||||||
Json::Value jvResult = doCommand (params, role, loadType, yield);
|
|
||||||
|
|
||||||
// Always report "status". On an error report the request as received.
|
|
||||||
if (jvResult.isMember ("error"))
|
|
||||||
{
|
|
||||||
jvResult[jss::status] = jss::error;
|
|
||||||
jvResult[jss::request] = params;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
jvResult[jss::status] = jss::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return logRPCError (jvResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
Json::Value RPCHandler::doCommand (
|
|
||||||
const Json::Value& params,
|
|
||||||
Role role,
|
|
||||||
Resource::Charge& loadType,
|
|
||||||
Yield yield)
|
|
||||||
{
|
|
||||||
if (role != Role::ADMIN)
|
|
||||||
{
|
{
|
||||||
// VFALCO NOTE Should we also add up the jtRPC jobs?
|
// VFALCO NOTE Should we also add up the jtRPC jobs?
|
||||||
//
|
//
|
||||||
int jc = getApp().getJobQueue ().getJobCountGE (jtCLIENT);
|
int jc = getApp().getJobQueue ().getJobCountGE (jtCLIENT);
|
||||||
if (jc > RPC::Tuning::maxJobQueueClients)
|
if (jc > Tuning::maxJobQueueClients)
|
||||||
{
|
{
|
||||||
WriteLog (lsDEBUG, RPCHandler) << "Too busy for command: " << jc;
|
WriteLog (lsDEBUG, RPCHandler) << "Too busy for command: " << jc;
|
||||||
return rpcError (rpcTOO_BUSY);
|
return rpcTOO_BUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.isMember ("command"))
|
if (!context.params.isMember ("command"))
|
||||||
return rpcError (rpcCOMMAND_MISSING);
|
return rpcCOMMAND_MISSING;
|
||||||
|
|
||||||
std::string strCommand = params[jss::command].asString ();
|
std::string strCommand = context.params[jss::command].asString ();
|
||||||
|
|
||||||
WriteLog (lsTRACE, RPCHandler) << "COMMAND:" << strCommand;
|
WriteLog (lsTRACE, RPCHandler) << "COMMAND:" << strCommand;
|
||||||
WriteLog (lsTRACE, RPCHandler) << "REQUEST:" << params;
|
WriteLog (lsTRACE, RPCHandler) << "REQUEST:" << context.params;
|
||||||
|
|
||||||
role_ = role;
|
auto handler = getHandler(strCommand);
|
||||||
|
|
||||||
auto handler = RPC::getHandler(strCommand);
|
|
||||||
|
|
||||||
if (!handler)
|
if (!handler)
|
||||||
return rpcError (rpcUNKNOWN_COMMAND);
|
return rpcUNKNOWN_COMMAND;
|
||||||
|
|
||||||
if (handler->role_ == Role::ADMIN && role_ != Role::ADMIN)
|
if (handler->role_ == Role::ADMIN && context.role != Role::ADMIN)
|
||||||
return rpcError (rpcNO_PERMISSION);
|
return rpcNO_PERMISSION;
|
||||||
|
|
||||||
if ((handler->condition_ & RPC::NEEDS_NETWORK_CONNECTION) &&
|
if ((handler->condition_ & NEEDS_NETWORK_CONNECTION) &&
|
||||||
(netOps_.getOperatingMode () < NetworkOPs::omSYNCING))
|
(context.netOps.getOperatingMode () < NetworkOPs::omSYNCING))
|
||||||
{
|
{
|
||||||
WriteLog (lsINFO, RPCHandler)
|
WriteLog (lsINFO, RPCHandler)
|
||||||
<< "Insufficient network mode for RPC: "
|
<< "Insufficient network mode for RPC: "
|
||||||
<< netOps_.strOperatingMode ();
|
<< context.netOps.strOperatingMode ();
|
||||||
|
|
||||||
return rpcError (rpcNO_NETWORK);
|
return rpcNO_NETWORK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getConfig ().RUN_STANDALONE
|
if (!getConfig ().RUN_STANDALONE
|
||||||
&& (handler->condition_ & RPC::NEEDS_CURRENT_LEDGER)
|
&& (handler->condition_ & NEEDS_CURRENT_LEDGER)
|
||||||
&& (getApp().getLedgerMaster().getValidatedLedgerAge() >
|
&& (getApp().getLedgerMaster().getValidatedLedgerAge() >
|
||||||
RPC::Tuning::maxValidatedLedgerAge))
|
Tuning::maxValidatedLedgerAge))
|
||||||
{
|
{
|
||||||
return rpcError (rpcNO_CURRENT);
|
return rpcNO_CURRENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((handler->condition_ & RPC::NEEDS_CLOSED_LEDGER) &&
|
if ((handler->condition_ & NEEDS_CLOSED_LEDGER) &&
|
||||||
!netOps_.getClosedLedger ())
|
!context.netOps.getClosedLedger ())
|
||||||
{
|
{
|
||||||
return rpcError (rpcNO_CLOSED);
|
return rpcNO_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = *handler;
|
||||||
|
return rpcSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Object, class Method>
|
||||||
|
Status callMethod (
|
||||||
|
Context& context, Method method, std::string const& name, Object& result)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LoadEvent::autoptr ev = getApp().getJobQueue().getLoadEventAP(
|
auto v = getApp().getJobQueue().getLoadEventAP(
|
||||||
jtGENERIC, "cmd:" + strCommand);
|
jtGENERIC, "cmd:" + name);
|
||||||
RPC::Context context {
|
return method (context, result);
|
||||||
params, loadType, netOps_, infoSub_, role_, yield};
|
|
||||||
Json::Value result (Json::objectValue);
|
|
||||||
handler->valueMethod_ (context, result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
WriteLog (lsINFO, RPCHandler) << "Caught throw: " << e.what ();
|
WriteLog (lsINFO, RPCHandler) << "Caught throw: " << e.what ();
|
||||||
|
|
||||||
if (loadType == Resource::feeReferenceRPC)
|
if (context.loadType == Resource::feeReferenceRPC)
|
||||||
loadType = Resource::feeExceptionRPC;
|
context.loadType = Resource::feeExceptionRPC;
|
||||||
|
|
||||||
return rpcError (rpcINTERNAL);
|
inject_error (rpcINTERNAL, result);
|
||||||
|
return rpcINTERNAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Method, class Object>
|
||||||
|
void getResult (
|
||||||
|
Context& context, Method method, Object& object, std::string const& name)
|
||||||
|
{
|
||||||
|
auto&& result = addObject (object, jss::result);
|
||||||
|
if (auto status = callMethod (context, method, name, result))
|
||||||
|
{
|
||||||
|
WriteLog (lsDEBUG, RPCErr) << "rpcError: " << status.toString();
|
||||||
|
result[jss::status] = jss::error;
|
||||||
|
result[jss::request] = context.params;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result[jss::status] = jss::success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Status doCommand (RPC::Context& context, Json::Value& result)
|
||||||
|
{
|
||||||
|
boost::optional <Handler const&> handler;
|
||||||
|
if (auto error = fillHandler (context, handler))
|
||||||
|
{
|
||||||
|
inject_error (error, result);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto method = handler->valueMethod_)
|
||||||
|
return callMethod (context, method, handler->name_, result);
|
||||||
|
|
||||||
|
return rpcUNKNOWN_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Execute an RPC command and store the results in a string. */
|
||||||
|
void executeRPC (RPC::Context& context, std::string& output)
|
||||||
|
{
|
||||||
|
boost::optional <Handler const&> handler;
|
||||||
|
if (auto error = fillHandler (context, handler))
|
||||||
|
{
|
||||||
|
auto wo = stringWriterObject (output);
|
||||||
|
auto&& sub = addObject (*wo, jss::result);
|
||||||
|
inject_error (error, sub);
|
||||||
|
}
|
||||||
|
else if (auto method = handler->objectMethod_)
|
||||||
|
{
|
||||||
|
auto wo = stringWriterObject (output);
|
||||||
|
getResult (context, method, *wo, handler->name_);
|
||||||
|
}
|
||||||
|
else if (auto method = handler->valueMethod_)
|
||||||
|
{
|
||||||
|
auto object = Json::Value (Json::objectValue);
|
||||||
|
getResult (context, method, object, handler->name_);
|
||||||
|
|
||||||
|
if (streamingRPC)
|
||||||
|
output = jsonAsString (object);
|
||||||
|
else
|
||||||
|
output = to_string (object);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can't ever get here.
|
||||||
|
assert (false);
|
||||||
|
throw RPC::JsonException ("RPC handler with no method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // RPC
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -71,5 +71,23 @@ void Status::fillJson (Json::Value& value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Status::message() const {
|
||||||
|
std::string result;
|
||||||
|
for (auto& m: messages_)
|
||||||
|
{
|
||||||
|
if (!result.empty())
|
||||||
|
result += '/';
|
||||||
|
result += m;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Status::toString() const {
|
||||||
|
if (*this)
|
||||||
|
return codeString() + ":" + message();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace RPC
|
} // namespace RPC
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -194,8 +194,7 @@ ServerHandlerImp::onRequest (HTTP::Session& session)
|
|||||||
|
|
||||||
RPC::Coroutine::YieldFunction yieldFunction =
|
RPC::Coroutine::YieldFunction yieldFunction =
|
||||||
[this, detach] (Yield const& y) { processSession (detach, y); };
|
[this, detach] (Yield const& y) { processSession (detach, y); };
|
||||||
RPC::Coroutine coroutine (yieldFunction);
|
runCoroutine (RPC::Coroutine (yieldFunction), m_jobQueue);
|
||||||
runCoroutine (std::move(coroutine), m_jobQueue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -317,14 +316,23 @@ ServerHandlerImp::processRequest (
|
|||||||
// Parse params
|
// Parse params
|
||||||
Json::Value params = jsonRPC ["params"];
|
Json::Value params = jsonRPC ["params"];
|
||||||
|
|
||||||
if (params.isNull ())
|
if (params.isNull () || params.empty())
|
||||||
params = Json::Value (Json::arrayValue);
|
params = Json::Value (Json::objectValue);
|
||||||
|
|
||||||
else if (!params.isArray ())
|
else if (!params.isArray () || params.size() != 1)
|
||||||
{
|
{
|
||||||
HTTPReply (400, "params unparseable", output);
|
HTTPReply (400, "params unparseable", output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
params = std::move (params[0u]);
|
||||||
|
if (!params.isObject())
|
||||||
|
{
|
||||||
|
HTTPReply (400, "params unparseable", output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VFALCO TODO Shouldn't we handle this earlier?
|
// VFALCO TODO Shouldn't we handle this earlier?
|
||||||
//
|
//
|
||||||
@@ -337,22 +345,57 @@ ServerHandlerImp::processRequest (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RPCHandler rpcHandler (m_networkOPs);
|
|
||||||
Resource::Charge loadType = Resource::feeReferenceRPC;
|
Resource::Charge loadType = Resource::feeReferenceRPC;
|
||||||
|
|
||||||
m_journal.debug << "Query: " << strMethod << params;
|
m_journal.debug << "Query: " << strMethod << params;
|
||||||
|
|
||||||
auto result = rpcHandler.doRpcCommand (
|
// Provide the JSON-RPC method as the field "command" in the request.
|
||||||
strMethod, params, role, loadType, yield);
|
params[jss::command] = strMethod;
|
||||||
m_journal.debug << "Reply: " << result;
|
WriteLog (lsTRACE, RPCHandler)
|
||||||
|
<< "doRpcCommand:" << strMethod << ":" << params;
|
||||||
|
|
||||||
|
RPC::Context context {params, loadType, m_networkOPs, role, nullptr, yield};
|
||||||
|
std::string response;
|
||||||
|
|
||||||
|
if (RPC::streamingRPC)
|
||||||
|
{
|
||||||
|
executeRPC (context, response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Json::Value result;
|
||||||
|
RPC::doCommand (context, result);
|
||||||
|
|
||||||
|
// Always report "status". On an error report the request as received.
|
||||||
|
if (result.isMember ("error"))
|
||||||
|
{
|
||||||
|
result[jss::status] = jss::error;
|
||||||
|
result[jss::request] = params;
|
||||||
|
WriteLog (lsDEBUG, RPCErr) <<
|
||||||
|
"rpcError: " << result ["error"] <<
|
||||||
|
": " << result ["error_message"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result[jss::status] = jss::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value reply (Json::objectValue);
|
||||||
|
reply[jss::result] = std::move (result);
|
||||||
|
response = to_string (reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
response += '\n';
|
||||||
usage.charge (loadType);
|
usage.charge (loadType);
|
||||||
|
|
||||||
Json::Value reply (Json::objectValue);
|
if (m_journal.debug.active())
|
||||||
reply[jss::result] = std::move (result);
|
{
|
||||||
auto response = to_string (reply);
|
static const int maxSize = 10000;
|
||||||
response += '\n';
|
if (response.size() <= maxSize)
|
||||||
|
m_journal.debug << "Reply: " << response;
|
||||||
|
else
|
||||||
|
m_journal.debug << "Reply: " << response.substr (0, maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
HTTPReply (200, response, output);
|
HTTPReply (200, response, output);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user