Skip to content

Commit

Permalink
Add support for handlers version selection
Browse files Browse the repository at this point in the history
  • Loading branch information
Bronek authored and Bronek Kozicki committed Oct 13, 2023
1 parent 26e27cc commit 079202e
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 46 deletions.
23 changes: 8 additions & 15 deletions src/ripple/rpc/handlers/LedgerHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <ripple/rpc/Role.h>
#include <ripple/rpc/Status.h>
#include <ripple/rpc/impl/Handler.h>
#include <ripple/rpc/impl/RPCHelpers.h>

namespace Json {
class Object;
Expand Down Expand Up @@ -58,23 +59,15 @@ class LedgerHandler
void
writeResult(Object&);

static char const*
name()
{
return "ledger";
}
static constexpr char const name[] = "ledger";

static Role
role()
{
return Role::USER;
}
static constexpr unsigned minApiVer = 1;

static Condition
condition()
{
return NO_CONDITION;
}
static constexpr unsigned maxApiVer = RPC::apiMaximumValidVersion;

static constexpr Role role = Role::USER;

static constexpr Condition condition = NO_CONDITION;

private:
JsonContext& context_;
Expand Down
23 changes: 8 additions & 15 deletions src/ripple/rpc/handlers/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#ifndef RIPPLED_RIPPLE_RPC_HANDLERS_VERSION_H
#define RIPPLED_RIPPLE_RPC_HANDLERS_VERSION_H

#include <ripple/rpc/impl/Handler.h>
#include <ripple/rpc/impl/RPCHelpers.h>

namespace ripple {
Expand All @@ -46,23 +47,15 @@ class VersionHandler
setVersion(obj, apiVersion_, betaEnabled_);
}

static char const*
name()
{
return "version";
}
static constexpr char const* name = "version";

static Role
role()
{
return Role::USER;
}
static constexpr unsigned minApiVer = 1;

static Condition
condition()
{
return NO_CONDITION;
}
static constexpr unsigned maxApiVer = RPC::apiMaximumValidVersion;

static constexpr Role role = Role::USER;

static constexpr Condition condition = NO_CONDITION;

private:
unsigned int apiVersion_;
Expand Down
83 changes: 67 additions & 16 deletions src/ripple/rpc/impl/Handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <ripple/rpc/impl/Handler.h>
#include <ripple/rpc/impl/RPCHelpers.h>

#include <map>

namespace ripple {
namespace RPC {
namespace {
Expand Down Expand Up @@ -57,6 +59,19 @@ handle(JsonContext& context, Object& object)
return status;
};

template <typename HandlerImpl>
Handler
handlerFrom()
{
return {
HandlerImpl::name,
&handle<Json::Value, HandlerImpl>,
HandlerImpl::role,
HandlerImpl::condition,
HandlerImpl::minApiVer,
HandlerImpl::maxApiVer};
}

Handler const handlerArray[]{
// Some handlers not specified here are added to the table via addHandler()
// Request-response methods
Expand Down Expand Up @@ -174,14 +189,39 @@ Handler const handlerArray[]{
class HandlerTable
{
private:
using handler_table_t = std::multimap<std::string, Handler>;

// Use with equal_range to enforce that API range of a newly added handler
// does not overlap with API range of an existing handler with same name
bool
overlappingApiVersion(
std::pair<handler_table_t::iterator, handler_table_t::iterator> range,
unsigned minVer,
unsigned maxVer)
{
assert(minVer <= maxVer);
assert(maxVer <= RPC::apiMaximumValidVersion);

for (; range.first != range.second; range.first++)
{
if (range.first->second.minApiVer_ <= maxVer &&
range.first->second.maxApiVer_ >= minVer)
return true;
}
return false;
}

template <std::size_t N>
explicit HandlerTable(const Handler (&entries)[N])
{
for (std::size_t i = 0; i < N; ++i)
for (auto const& entry : entries)
{
auto const& entry = entries[i];
assert(table_.find(entry.name_) == table_.end());
table_[entry.name_] = entry;
assert(!overlappingApiVersion(
table_.equal_range(entry.name_),
entry.minApiVer_,
entry.maxApiVer_));

table_.insert({entry.name_, entry});
}

// This is where the new-style handlers are added.
Expand All @@ -205,36 +245,47 @@ class HandlerTable
version > (betaEnabled ? RPC::apiBetaVersion
: RPC::apiMaximumSupportedVersion))
return nullptr;
auto i = table_.find(name);
return i == table_.end() ? nullptr : &i->second;

auto const range = table_.equal_range(name);
auto const i = std::find_if(
range.first, range.second, [version](auto const& entry) {
return version >= entry.second.minApiVer_ &&
version <= entry.second.maxApiVer_;
});

return i == range.second ? nullptr : &i->second;
}

std::vector<char const*>
getHandlerNames() const
{
std::vector<char const*> ret;
ret.reserve(table_.size());
for (auto const& i : table_)
ret.push_back(i.second.name_);
{
// Note, table_ is always ordered, allowing such a simple check
if (ret.empty() || std::strcmp(ret.back(), i.second.name_) != 0)
ret.push_back(i.second.name_);
}

return ret;
}

private:
std::map<std::string, Handler> table_;
handler_table_t table_;

template <class HandlerImpl>
void
addHandler()
{
assert(table_.find(HandlerImpl::name()) == table_.end());
static_assert(HandlerImpl::minApiVer <= HandlerImpl::maxApiVer);
static_assert(HandlerImpl::maxApiVer <= RPC::apiMaximumValidVersion);

Handler h;
h.name_ = HandlerImpl::name();
h.valueMethod_ = &handle<Json::Value, HandlerImpl>;
h.role_ = HandlerImpl::role();
h.condition_ = HandlerImpl::condition();
assert(!overlappingApiVersion(
table_.equal_range(HandlerImpl::name),
HandlerImpl::minApiVer,
HandlerImpl::maxApiVer));

table_[HandlerImpl::name()] = h;
table_.insert({HandlerImpl::name, handlerFrom<HandlerImpl>()});
}
};

Expand Down
4 changes: 4 additions & 0 deletions src/ripple/rpc/impl/Handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <ripple/core/Config.h>
#include <ripple/rpc/RPCHandler.h>
#include <ripple/rpc/Status.h>
#include <ripple/rpc/impl/RPCHelpers.h>
#include <ripple/rpc/impl/Tuning.h>
#include <vector>

Expand Down Expand Up @@ -52,6 +53,9 @@ struct Handler
Method<Json::Value> valueMethod_;
Role role_;
RPC::Condition condition_;

unsigned minApiVer_ = 1;
unsigned maxApiVer_ = apiMaximumValidVersion;
};

Handler const*
Expand Down
2 changes: 2 additions & 0 deletions src/ripple/rpc/impl/RPCHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,12 @@ constexpr unsigned int apiVersionIfUnspecified = 1;
constexpr unsigned int apiMinimumSupportedVersion = 1;
constexpr unsigned int apiMaximumSupportedVersion = 1;
constexpr unsigned int apiBetaVersion = 2;
constexpr unsigned int apiMaximumValidVersion = apiBetaVersion;

static_assert(apiMinimumSupportedVersion >= apiVersionIfUnspecified);
static_assert(apiMaximumSupportedVersion >= apiMinimumSupportedVersion);
static_assert(apiBetaVersion >= apiMaximumSupportedVersion);
static_assert(apiMaximumValidVersion >= apiMaximumSupportedVersion);

template <class Object>
void
Expand Down

0 comments on commit 079202e

Please sign in to comment.