diff --git a/src/ripple/rpc/RPCHandler.h b/src/ripple/rpc/RPCHandler.h index fade0b0d11..3f62e5b8d9 100644 --- a/src/ripple/rpc/RPCHandler.h +++ b/src/ripple/rpc/RPCHandler.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace ripple { @@ -34,16 +35,20 @@ public: explicit RPCHandler ( NetworkOPs& netOps, InfoSub::pointer infoSub = nullptr); + using Yield = RPC::Yield; + Json::Value doCommand ( Json::Value const& request, Role role, - Resource::Charge& loadType); + Resource::Charge& loadType, + Yield yield = {}); Json::Value doRpcCommand ( std::string const& command, Json::Value const& params, Role role, - Resource::Charge& loadType); + Resource::Charge& loadType, + Yield yield = {}); private: NetworkOPs& netOps_; diff --git a/src/ripple/rpc/handlers/Handlers.h b/src/ripple/rpc/handlers/Handlers.h index 5b89853c68..ca08c1d898 100644 --- a/src/ripple/rpc/handlers/Handlers.h +++ b/src/ripple/rpc/handlers/Handlers.h @@ -38,7 +38,6 @@ Json::Value doFeature (RPC::Context&); Json::Value doFetchInfo (RPC::Context&); Json::Value doGetCounts (RPC::Context&); Json::Value doInternal (RPC::Context&); -Json::Value doLedger (RPC::Context&); Json::Value doLedgerAccept (RPC::Context&); Json::Value doLedgerCleaner (RPC::Context&); Json::Value doLedgerClosed (RPC::Context&); diff --git a/src/ripple/rpc/handlers/Ledger.cpp b/src/ripple/rpc/handlers/Ledger.cpp index 812053763a..60599ef2f4 100644 --- a/src/ripple/rpc/handlers/Ledger.cpp +++ b/src/ripple/rpc/handlers/Ledger.cpp @@ -17,77 +17,73 @@ */ //============================================================================== +#include #include +#include +#include +#include #include namespace ripple { +namespace RPC { -// ledger [id|index|current|closed] [full] -// { -// ledger: 'current' | 'closed' | | , // optional -// full: true | false // optional, defaults to false. -// } -Json::Value doLedger (RPC::Context& context) +LedgerHandler::LedgerHandler (Context& context) : context_ (context) { - if (!context.params.isMember ("ledger") - && !context.params.isMember ("ledger_hash") - && !context.params.isMember ("ledger_index")) +} + +Status LedgerHandler::check (Json::Value& error) +{ + bool needsLedger = context_.params.isMember (jss::ledger) || + context_.params.isMember (jss::ledger_hash) || + context_.params.isMember (jss::ledger_index); + if (!needsLedger) + return Status::OK; + + lookupResult_ = RPC::lookupLedger ( + context_.params, ledger_, context_.netOps); + + if (!ledger_) { - Json::Value ret (Json::objectValue), current (Json::objectValue), - closed (Json::objectValue); - - getApp().getLedgerMaster ().getCurrentLedger ()->addJson (current, 0); - getApp().getLedgerMaster ().getClosedLedger ()->addJson (closed, 0); - - ret["open"] = current; - ret["closed"] = closed; - - return ret; + error = lookupResult_; + auto code = error_code_i (error[jss::error_code].asInt()); + return {code, {error[jss::error_message].asString()}}; } - Ledger::pointer lpLedger; - Json::Value jvResult = RPC::lookupLedger ( - context.params, lpLedger, context.netOps); - - if (!lpLedger) - return jvResult; - - bool bFull = context.params.isMember ("full") - && context.params["full"].asBool (); - bool bTransactions = context.params.isMember ("transactions") - && context.params["transactions"].asBool (); - bool bAccounts = context.params.isMember ("accounts") - && context.params["accounts"].asBool (); - bool bExpand = context.params.isMember ("expand") - && context.params["expand"].asBool (); - int iOptions = (bFull ? LEDGER_JSON_FULL : 0) - | (bExpand ? LEDGER_JSON_EXPAND : 0) - | (bTransactions ? LEDGER_JSON_DUMP_TXRP : 0) - | (bAccounts ? LEDGER_JSON_DUMP_STATE : 0); + bool bFull = context_.params.isMember (jss::full) + && context_.params[jss::full].asBool (); + bool bTransactions = context_.params.isMember (jss::transactions) + && context_.params[jss::transactions].asBool (); + bool bAccounts = context_.params.isMember (jss::accounts) + && context_.params[jss::accounts].asBool (); + bool bExpand = context_.params.isMember (jss::expand) + && context_.params[jss::expand].asBool (); + options_ = (bFull ? LEDGER_JSON_FULL : 0) + | (bExpand ? LEDGER_JSON_EXPAND : 0) + | (bTransactions ? LEDGER_JSON_DUMP_TXRP : 0) + | (bAccounts ? LEDGER_JSON_DUMP_STATE : 0); if (bFull || bAccounts) { - - if (context.role != Role::ADMIN) + if (context_.role != Role::ADMIN) { // Until some sane way to get full ledgers has been implemented, // disallow retrieving all state nodes. - return rpcError (rpcNO_PERMISSION); + error = rpcError (rpcNO_PERMISSION); + return rpcNO_PERMISSION; } if (getApp().getFeeTrack().isLoadedLocal() && - context.role != Role::ADMIN) + context_.role != Role::ADMIN) { - WriteLog (lsDEBUG, Peer) << "Too busy to give full ledger"; - return rpcError(rpcTOO_BUSY); + error = rpcError(rpcTOO_BUSY); + return rpcTOO_BUSY; } - context.loadType = Resource::feeHighBurdenRPC; + context_.loadType = Resource::feeHighBurdenRPC; } - - lpLedger->addJson (jvResult, iOptions); - - return jvResult; + std::cerr << "!!! LedgerHandler::check FIVE - true\n"; + return Status::OK; } +} // RPC } // ripple diff --git a/src/ripple/rpc/handlers/Ledger.h b/src/ripple/rpc/handlers/Ledger.h new file mode 100644 index 0000000000..34794b224f --- /dev/null +++ b/src/ripple/rpc/handlers/Ledger.h @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLED_RIPPLE_RPC_HANDLERS_LEDGER_H +#define RIPPLED_RIPPLE_RPC_HANDLERS_LEDGER_H + +#include +#include +#include +#include + +namespace ripple { +namespace RPC { + +class Object; + +// ledger [id|index|current|closed] [full] +// { +// ledger: 'current' | 'closed' | | , // optional +// full: true | false // optional, defaults to false. +// } + +class LedgerHandler { +public: + explicit LedgerHandler (Context&); + + Status check (Json::Value& error); + + template + void writeResult (Object&); + + static const char* const name() + { + return "ledger"; + } + + static Role role() + { + return Role::USER; + } + + static Condition condition() + { + return NEEDS_NETWORK_CONNECTION; + } + +private: + Context& context_; + Ledger::pointer ledger_; + Json::Value lookupResult_; + int options_; +}; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// Implementation. + +template +void LedgerHandler::writeResult (Object& value) +{ + if (ledger_) + { + RPC::copyFrom (value, lookupResult_); + addJson (*ledger_, value, options_, context_.yield); + } + else + { + auto& master = getApp().getLedgerMaster (); + auto& yield = context_.yield; + { + auto&& closed = RPC::addObject (value, jss::closed); + addJson (*master.getClosedLedger(), closed, 0, yield); + } + { + auto&& open = RPC::addObject (value, jss::open); + addJson (*master.getCurrentLedger(), open, 0, yield); + } + + } +} + +} // RPC +} // ripple + +#endif diff --git a/src/ripple/rpc/impl/Context.h b/src/ripple/rpc/impl/Context.h index b555f8b96d..2a03a4270b 100644 --- a/src/ripple/rpc/impl/Context.h +++ b/src/ripple/rpc/impl/Context.h @@ -21,6 +21,7 @@ #define RIPPLE_RPC_CONTEXT #include +#include #include namespace ripple { @@ -34,6 +35,7 @@ struct Context NetworkOPs& netOps; InfoSub::pointer infoSub; Role role; + RPC::Yield yield; }; } // RPC diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index 90375d66b3..eb5fbfc9fa 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -24,11 +24,28 @@ namespace ripple { namespace RPC { namespace { +/** Adjust an old-style handler to be call-by-reference. */ +template +Handler::Method byRef (Function const& f) +{ + return [f] (Context& context, Json::Value& result) + { + result = f (context); + return Status(); + }; +} + class HandlerTable { public: - HandlerTable(std::vector const& entries) { + HandlerTable (std::vector const& entries) { for (auto& entry: entries) + { + assert (table_.find(entry.name_) == table_.end()); table_[entry.name_] = entry; + } + + // This is where the new-style handlers are added. + addHandler(); } const Handler* getHandler(std::string name) { @@ -38,75 +55,109 @@ class HandlerTable { private: std::map table_; + + template + void addHandler() + { + assert (table_.find(Impl::name()) == table_.end()); + auto valueMethod = [] (Context& context, Json::Value& object) + { + Impl handler (context); + auto status = handler.check (object); + if (!status) + handler.writeResult (object); + return status; + }; + + auto objectMethod = [] (Context& context, Object& object) + { + Impl handler (context); + Json::Value error; + auto status = handler.check (error); + if (!status) + handler.writeResult (object); + else + RPC::copyFrom (object, error); + return status; + }; + + auto handler = Handler { + Impl::name(), + valueMethod, + Impl::role(), + Impl::condition(), + objectMethod}; + + table_[Impl::name()] = handler; + }; }; HandlerTable HANDLERS({ // Request-response methods - { "account_info", &doAccountInfo, Role::USER, NEEDS_CURRENT_LEDGER }, - { "account_currencies", &doAccountCurrencies, Role::USER, NEEDS_CURRENT_LEDGER }, - { "account_lines", &doAccountLines, Role::USER, NEEDS_CURRENT_LEDGER }, - { "account_offers", &doAccountOffers, Role::USER, NEEDS_CURRENT_LEDGER }, - { "account_tx", &doAccountTxSwitch, Role::USER, NEEDS_NETWORK_CONNECTION }, - { "blacklist", &doBlackList, Role::ADMIN, NO_CONDITION }, - { "book_offers", &doBookOffers, Role::USER, NEEDS_CURRENT_LEDGER }, - { "can_delete", &doCanDelete, Role::ADMIN, NO_CONDITION }, - { "connect", &doConnect, Role::ADMIN, NO_CONDITION }, - { "consensus_info", &doConsensusInfo, Role::ADMIN, NO_CONDITION }, - { "get_counts", &doGetCounts, Role::ADMIN, NO_CONDITION }, - { "internal", &doInternal, Role::ADMIN, NO_CONDITION }, - { "feature", &doFeature, Role::ADMIN, NO_CONDITION }, - { "fetch_info", &doFetchInfo, Role::ADMIN, NO_CONDITION }, - { "ledger", &doLedger, Role::USER, NEEDS_NETWORK_CONNECTION }, - { "ledger_accept", &doLedgerAccept, Role::ADMIN, NEEDS_CURRENT_LEDGER }, - { "ledger_cleaner", &doLedgerCleaner, Role::ADMIN, NEEDS_NETWORK_CONNECTION }, - { "ledger_closed", &doLedgerClosed, Role::USER, NEEDS_CLOSED_LEDGER }, - { "ledger_current", &doLedgerCurrent, Role::USER, NEEDS_CURRENT_LEDGER }, - { "ledger_data", &doLedgerData, Role::USER, NEEDS_CURRENT_LEDGER }, - { "ledger_entry", &doLedgerEntry, Role::USER, NEEDS_CURRENT_LEDGER }, - { "ledger_header", &doLedgerHeader, Role::USER, NEEDS_CURRENT_LEDGER }, - { "ledger_request", &doLedgerRequest, Role::ADMIN, NO_CONDITION }, - { "log_level", &doLogLevel, Role::ADMIN, NO_CONDITION }, - { "logrotate", &doLogRotate, Role::ADMIN, NO_CONDITION }, - { "owner_info", &doOwnerInfo, Role::USER, NEEDS_CURRENT_LEDGER }, - { "peers", &doPeers, Role::ADMIN, NO_CONDITION }, - { "path_find", &doPathFind, Role::USER, NEEDS_CURRENT_LEDGER }, - { "ping", &doPing, Role::USER, NO_CONDITION }, - { "print", &doPrint, Role::ADMIN, NO_CONDITION }, -// { "profile", &doProfile, Role::USER, NEEDS_CURRENT_LEDGER }, - { "proof_create", &doProofCreate, Role::ADMIN, NO_CONDITION }, - { "proof_solve", &doProofSolve, Role::ADMIN, NO_CONDITION }, - { "proof_verify", &doProofVerify, Role::ADMIN, NO_CONDITION }, - { "random", &doRandom, Role::USER, NO_CONDITION }, - { "ripple_path_find", &doRipplePathFind, Role::USER, NEEDS_CURRENT_LEDGER }, - { "sign", &doSign, Role::USER, NO_CONDITION }, - { "submit", &doSubmit, Role::USER, NEEDS_CURRENT_LEDGER }, - { "server_info", &doServerInfo, Role::USER, NO_CONDITION }, - { "server_state", &doServerState, Role::USER, NO_CONDITION }, - { "sms", &doSMS, Role::ADMIN, NO_CONDITION }, - { "stop", &doStop, Role::ADMIN, NO_CONDITION }, - { "transaction_entry", &doTransactionEntry, Role::USER, NEEDS_CURRENT_LEDGER }, - { "tx", &doTx, Role::USER, NEEDS_NETWORK_CONNECTION }, - { "tx_history", &doTxHistory, Role::USER, NO_CONDITION }, - { "unl_add", &doUnlAdd, Role::ADMIN, NO_CONDITION }, - { "unl_delete", &doUnlDelete, Role::ADMIN, NO_CONDITION }, - { "unl_list", &doUnlList, Role::ADMIN, NO_CONDITION }, - { "unl_load", &doUnlLoad, Role::ADMIN, NO_CONDITION }, - { "unl_network", &doUnlNetwork, Role::ADMIN, NO_CONDITION }, - { "unl_reset", &doUnlReset, Role::ADMIN, NO_CONDITION }, - { "unl_score", &doUnlScore, Role::ADMIN, NO_CONDITION }, - { "validation_create", &doValidationCreate, Role::ADMIN, NO_CONDITION }, - { "validation_seed", &doValidationSeed, Role::ADMIN, NO_CONDITION }, - { "wallet_accounts", &doWalletAccounts, Role::USER, NEEDS_CURRENT_LEDGER }, - { "wallet_propose", &doWalletPropose, Role::ADMIN, NO_CONDITION }, - { "wallet_seed", &doWalletSeed, Role::ADMIN, NO_CONDITION }, + { "account_info", byRef (&doAccountInfo), Role::USER, NEEDS_CURRENT_LEDGER }, + { "account_currencies", byRef (&doAccountCurrencies), Role::USER, NEEDS_CURRENT_LEDGER }, + { "account_lines", byRef (&doAccountLines), Role::USER, NEEDS_CURRENT_LEDGER }, + { "account_offers", byRef (&doAccountOffers), Role::USER, NEEDS_CURRENT_LEDGER }, + { "account_tx", byRef (&doAccountTxSwitch), Role::USER, NEEDS_NETWORK_CONNECTION }, + { "blacklist", byRef (&doBlackList), Role::ADMIN, NO_CONDITION }, + { "book_offers", byRef (&doBookOffers), Role::USER, NEEDS_CURRENT_LEDGER }, + { "can_delete", byRef (&doCanDelete), Role::ADMIN, NO_CONDITION }, + { "connect", byRef (&doConnect), Role::ADMIN, NO_CONDITION }, + { "consensus_info", byRef (&doConsensusInfo), Role::ADMIN, NO_CONDITION }, + { "get_counts", byRef (&doGetCounts), Role::ADMIN, NO_CONDITION }, + { "internal", byRef (&doInternal), Role::ADMIN, NO_CONDITION }, + { "feature", byRef (&doFeature), Role::ADMIN, NO_CONDITION }, + { "fetch_info", byRef (&doFetchInfo), Role::ADMIN, NO_CONDITION }, + { "ledger_accept", byRef (&doLedgerAccept), Role::ADMIN, NEEDS_CURRENT_LEDGER }, + { "ledger_cleaner", byRef (&doLedgerCleaner), Role::ADMIN, NEEDS_NETWORK_CONNECTION }, + { "ledger_closed", byRef (&doLedgerClosed), Role::USER, NEEDS_CLOSED_LEDGER }, + { "ledger_current", byRef (&doLedgerCurrent), Role::USER, NEEDS_CURRENT_LEDGER }, + { "ledger_data", byRef (&doLedgerData), Role::USER, NEEDS_CURRENT_LEDGER }, + { "ledger_entry", byRef (&doLedgerEntry), Role::USER, NEEDS_CURRENT_LEDGER }, + { "ledger_header", byRef (&doLedgerHeader), Role::USER, NEEDS_CURRENT_LEDGER }, + { "ledger_request", byRef (&doLedgerRequest), Role::ADMIN, NO_CONDITION }, + { "log_level", byRef (&doLogLevel), Role::ADMIN, NO_CONDITION }, + { "logrotate", byRef (&doLogRotate), Role::ADMIN, NO_CONDITION }, + { "owner_info", byRef (&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER }, + { "peers", byRef (&doPeers), Role::ADMIN, NO_CONDITION }, + { "path_find", byRef (&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER }, + { "ping", byRef (&doPing), Role::USER, NO_CONDITION }, + { "print", byRef (&doPrint), Role::ADMIN, NO_CONDITION }, +// { "profile", byRef (&doProfile), Role::USER, NEEDS_CURRENT_LEDGER }, + { "proof_create", byRef (&doProofCreate), Role::ADMIN, NO_CONDITION }, + { "proof_solve", byRef (&doProofSolve), Role::ADMIN, NO_CONDITION }, + { "proof_verify", byRef (&doProofVerify), Role::ADMIN, NO_CONDITION }, + { "random", byRef (&doRandom), Role::USER, NO_CONDITION }, + { "ripple_path_find", byRef (&doRipplePathFind), Role::USER, NEEDS_CURRENT_LEDGER }, + { "sign", byRef (&doSign), Role::USER, NO_CONDITION }, + { "submit", byRef (&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER }, + { "server_info", byRef (&doServerInfo), Role::USER, NO_CONDITION }, + { "server_state", byRef (&doServerState), Role::USER, NO_CONDITION }, + { "sms", byRef (&doSMS), Role::ADMIN, NO_CONDITION }, + { "stop", byRef (&doStop), Role::ADMIN, NO_CONDITION }, + { "transaction_entry", byRef (&doTransactionEntry), Role::USER, NEEDS_CURRENT_LEDGER }, + { "tx", byRef (&doTx), Role::USER, NEEDS_NETWORK_CONNECTION }, + { "tx_history", byRef (&doTxHistory), Role::USER, NO_CONDITION }, + { "unl_add", byRef (&doUnlAdd), Role::ADMIN, NO_CONDITION }, + { "unl_delete", byRef (&doUnlDelete), Role::ADMIN, NO_CONDITION }, + { "unl_list", byRef (&doUnlList), Role::ADMIN, NO_CONDITION }, + { "unl_load", byRef (&doUnlLoad), Role::ADMIN, NO_CONDITION }, + { "unl_network", byRef (&doUnlNetwork), Role::ADMIN, NO_CONDITION }, + { "unl_reset", byRef (&doUnlReset), Role::ADMIN, NO_CONDITION }, + { "unl_score", byRef (&doUnlScore), Role::ADMIN, NO_CONDITION }, + { "validation_create", byRef (&doValidationCreate), Role::ADMIN, NO_CONDITION }, + { "validation_seed", byRef (&doValidationSeed), Role::ADMIN, NO_CONDITION }, + { "wallet_accounts", byRef (&doWalletAccounts), Role::USER, NEEDS_CURRENT_LEDGER }, + { "wallet_propose", byRef (&doWalletPropose), Role::ADMIN, NO_CONDITION }, + { "wallet_seed", byRef (&doWalletSeed), Role::ADMIN, NO_CONDITION }, // Evented methods - { "subscribe", &doSubscribe, Role::USER, NO_CONDITION }, - { "unsubscribe", &doUnsubscribe, Role::USER, NO_CONDITION }, + { "subscribe", byRef (&doSubscribe), Role::USER, NO_CONDITION }, + { "unsubscribe", byRef (&doUnsubscribe), Role::USER, NO_CONDITION }, }); } // namespace -const Handler* getHandler(std::string name) { +const Handler* getHandler(std::string const& name) { return HANDLERS.getHandler(name); } diff --git a/src/ripple/rpc/impl/Handler.h b/src/ripple/rpc/impl/Handler.h index 9c00ed08f1..c3bf002cc7 100644 --- a/src/ripple/rpc/impl/Handler.h +++ b/src/ripple/rpc/impl/Handler.h @@ -22,10 +22,13 @@ #include #include +#include namespace ripple { namespace RPC { +class Object; + // Under what condition can we call this RPC? enum Condition { NO_CONDITION = 0, @@ -36,15 +39,17 @@ enum Condition { struct Handler { - typedef Json::Value (*Method) (Context&); + template + using Method = std::function ; const char* name_; - Method method_; + Method valueMethod_; Role role_; RPC::Condition condition_; + Method objectMethod_; }; -const Handler* getHandler(std::string name); +const Handler* getHandler (std::string const&); /** Return a Json::objectValue with a single entry. */ template diff --git a/src/ripple/rpc/impl/RPCHandler.cpp b/src/ripple/rpc/impl/RPCHandler.cpp index 35f7273fbc..788ecb2de5 100644 --- a/src/ripple/rpc/impl/RPCHandler.cpp +++ b/src/ripple/rpc/impl/RPCHandler.cpp @@ -43,7 +43,8 @@ Json::Value RPCHandler::doRpcCommand ( const std::string& strMethod, Json::Value const& jvParams, Role role, - Resource::Charge& loadType) + Resource::Charge& loadType, + Yield yield) { WriteLog (lsTRACE, RPCHandler) << "doRpcCommand:" << strMethod << ":" << jvParams; @@ -60,7 +61,7 @@ Json::Value RPCHandler::doRpcCommand ( // Provide the JSON-RPC method as the field "command" in the request. params[jss::command] = strMethod; - Json::Value jvResult = doCommand (params, role, loadType); + Json::Value jvResult = doCommand (params, role, loadType, yield); // Always report "status". On an error report the request as received. if (jvResult.isMember ("error")) @@ -79,7 +80,8 @@ Json::Value RPCHandler::doRpcCommand ( Json::Value RPCHandler::doCommand ( const Json::Value& params, Role role, - Resource::Charge& loadType) + Resource::Charge& loadType, + Yield yield) { if (role != Role::ADMIN) { @@ -139,9 +141,10 @@ Json::Value RPCHandler::doCommand ( { LoadEvent::autoptr ev = getApp().getJobQueue().getLoadEventAP( jtGENERIC, "cmd:" + strCommand); - RPC::Context context {params, loadType, netOps_, infoSub_, role_}; - auto result = handler->method_(context); - assert (result.isObject()); + RPC::Context context { + params, loadType, netOps_, infoSub_, role_, yield}; + Json::Value result (Json::objectValue); + handler->valueMethod_ (context, result); return result; } catch (std::exception& e)