// Recursive function to convert JSON --> Lua table static bool push_json_value_helper(lua_State *L, const Json::Value &value, int nullindex) { switch(value.type()) { case Json::nullValue: default: lua_pushvalue(L, nullindex); break; case Json::intValue: lua_pushinteger(L, value.asInt()); break; case Json::uintValue: lua_pushinteger(L, value.asUInt()); break; case Json::realValue: lua_pushnumber(L, value.asDouble()); break; case Json::stringValue: { const char *str = value.asCString(); lua_pushstring(L, str ? str : ""); } break; case Json::booleanValue: lua_pushboolean(L, value.asInt()); break; case Json::arrayValue: lua_newtable(L); for (Json::Value::const_iterator it = value.begin(); it != value.end(); ++it) { push_json_value_helper(L, *it, nullindex); lua_rawseti(L, -2, it.index() + 1); } break; case Json::objectValue: lua_newtable(L); for (Json::Value::const_iterator it = value.begin(); it != value.end(); ++it) { #ifndef JSONCPP_STRING const char *str = it.memberName(); lua_pushstring(L, str ? str : ""); #else std::string str = it.name(); lua_pushstring(L, str.c_str()); #endif push_json_value_helper(L, *it, nullindex); lua_rawset(L, -3); } break; } return true; }
// { // account: <account>|<account_public_key> // account_index: <number> // optional, defaults to 0. // ledger_hash : <ledger> // ledger_index : <ledger_index> // limit: integer // optional // marker: opaque // optional, resume previous query // } Json::Value doAccountOffers (RPC::Context& context) { auto const& params (context.params); if (! params.isMember (jss::account)) return RPC::missing_field_error (jss::account); Ledger::pointer ledger; Json::Value result (RPC::lookupLedger (params, ledger, context.netOps)); if (! ledger) return result; std::string strIdent (params[jss::account].asString ()); bool bIndex (params.isMember (jss::account_index)); int const iIndex (bIndex ? params[jss::account_index].asUInt () : 0); DivvyAddress divvyAddress; Json::Value const jv = RPC::accountFromString ( divvyAddress, bIndex, strIdent, iIndex, false); if (! jv.empty ()) { for (Json::Value::const_iterator it (jv.begin ()); it != jv.end (); ++it) result[it.memberName ()] = it.key (); return result; } // Get info on account. result[jss::account] = divvyAddress.humanAccountID (); if (bIndex) result[jss::account_index] = iIndex; if (! ledger->exists(getAccountRootIndex( divvyAddress.getAccountID()))) return rpcError (rpcACT_NOT_FOUND); unsigned int limit; if (params.isMember (jss::limit)) { auto const& jvLimit (params[jss::limit]); if (! jvLimit.isIntegral ()) return RPC::expected_field_error (jss::limit, "unsigned integer"); limit = jvLimit.isUInt () ? jvLimit.asUInt () : std::max (0, jvLimit.asInt ()); if (context.role != Role::ADMIN) { limit = std::max (RPC::Tuning::minOffersPerRequest, std::min (limit, RPC::Tuning::maxOffersPerRequest)); } } else { limit = RPC::Tuning::defaultOffersPerRequest; } AccountID const& raAccount (divvyAddress.getAccountID ()); Json::Value& jsonOffers (result[jss::offers] = Json::arrayValue); std::vector <std::shared_ptr<SLE const>> offers; unsigned int reserve (limit); uint256 startAfter; std::uint64_t startHint; if (params.isMember(jss::marker)) { // We have a start point. Use limit - 1 from the result and use the // very last one for the resume. Json::Value const& marker (params[jss::marker]); if (! marker.isString ()) return RPC::expected_field_error (jss::marker, "string"); startAfter.SetHex (marker.asString ()); auto const sleOffer = fetch (*ledger, startAfter, getApp().getSLECache()); if (sleOffer == nullptr || sleOffer->getType () != ltOFFER || raAccount != sleOffer->getFieldAccount160 (sfAccount)) { return rpcError (rpcINVALID_PARAMS); } startHint = sleOffer->getFieldU64(sfOwnerNode); // Caller provided the first offer (startAfter), add it as first result Json::Value& obj (jsonOffers.append (Json::objectValue)); sleOffer->getFieldAmount (sfTakerPays).setJson (obj[jss::taker_pays]); sleOffer->getFieldAmount (sfTakerGets).setJson (obj[jss::taker_gets]); obj[jss::seq] = sleOffer->getFieldU32 (sfSequence); obj[jss::flags] = sleOffer->getFieldU32 (sfFlags); offers.reserve (reserve); } else { startHint = 0; // We have no start point, limit should be one higher than requested. offers.reserve (++reserve); } if (! forEachItemAfter(*ledger, raAccount, getApp().getSLECache(), startAfter, startHint, reserve, [&offers](std::shared_ptr<SLE const> const& offer) { if (offer->getType () == ltOFFER) { offers.emplace_back (offer); return true; } return false; })) { return rpcError (rpcINVALID_PARAMS); } if (offers.size () == reserve) { result[jss::limit] = limit; result[jss::marker] = to_string (offers.back ()->getIndex ()); offers.pop_back (); } for (auto const& offer : offers) { Json::Value& obj (jsonOffers.append (Json::objectValue)); offer->getFieldAmount (sfTakerPays).setJson (obj[jss::taker_pays]); offer->getFieldAmount (sfTakerGets).setJson (obj[jss::taker_gets]); obj[jss::seq] = offer->getFieldU32 (sfSequence); obj[jss::flags] = offer->getFieldU32 (sfFlags); } context.loadType = Resource::feeMediumBurdenRPC; return result; }