Skip to content

Commit

Permalink
Facilitate automatic JSON-RPC object lookup (#1808)
Browse files Browse the repository at this point in the history
* Facilitate automatic JSON-RPC object lookup

* Lock resources

* fix clang warning

---------

Co-authored-by: Pierre Wielders <[email protected]>
  • Loading branch information
sebaszm and pwielders authored Dec 17, 2024
1 parent c3c006d commit bc58299
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 15 deletions.
69 changes: 67 additions & 2 deletions Source/core/JSONRPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -820,9 +820,13 @@ POP_WARNING()
{
using ARG0 = typename std::decay<typename TypeTraits::func_traits<METHOD>::template argument<0>::type>::type;
using ARG1 = typename std::decay<typename TypeTraits::func_traits<METHOD>::template argument<1>::type>::type;
using ARG2 = typename std::decay<typename TypeTraits::func_traits<METHOD>::template argument<2>::type>::type;
constexpr auto HAS_CONTEXT = std::is_same<ARG0, Context>::value;
constexpr auto HAS_INDEX = (std::is_same<ARG0, string>::value | std::is_same<ARG1, string>::value | std::is_same<ARG2, string>::value);
constexpr auto HAS_INSTANCEID = (std::is_same<ARG0, uint32_t>::value | std::is_same<ARG1, uint32_t>::value);

InternalRegister<INBOUND, OUTBOUND, METHOD>(
::TemplateIntToType<std::is_same<ARG0, Context>::value | (std::is_same<ARG0, string>::value << 1) | (std::is_same<ARG1, string>::value << 1) | (std::is_same<ARG0, uint32_t>::value << 2)>(),
::TemplateIntToType<HAS_CONTEXT | (HAS_INDEX << 1) | (HAS_INSTANCEID << 2)>(),
::TemplateIntToType<std::is_same<INBOUND, void>::value>(),
::TemplateIntToType<std::is_same<OUTBOUND, void>::value>(),
methodName,
Expand All @@ -833,9 +837,13 @@ POP_WARNING()
{
using ARG0 = typename std::decay<typename TypeTraits::func_traits<METHOD>::template argument<0>::type>::type;
using ARG1 = typename std::decay<typename TypeTraits::func_traits<METHOD>::template argument<1>::type>::type;
using ARG2 = typename std::decay<typename TypeTraits::func_traits<METHOD>::template argument<2>::type>::type;
constexpr auto HAS_CONTEXT = std::is_same<ARG0, Context>::value;
constexpr auto HAS_INDEX = (std::is_same<ARG0, string>::value | std::is_same<ARG1, string>::value | std::is_same<ARG2, string>::value);
constexpr auto HAS_INSTANCEID = (std::is_same<ARG0, uint32_t>::value | std::is_same<ARG1, uint32_t>::value);

InternalRegister<INBOUND, OUTBOUND, METHOD, REALOBJECT>(
::TemplateIntToType<std::is_same<ARG0, Context>::value | (std::is_same<ARG0, string>::value << 1) | (std::is_same<ARG1, string>::value << 1) | (std::is_same<ARG0, uint32_t>::value << 2)>(),
::TemplateIntToType<HAS_CONTEXT | (HAS_INDEX << 1) | (HAS_INSTANCEID << 2)>(),
::TemplateIntToType<std::is_same<INBOUND, void>::value>(),
::TemplateIntToType<std::is_same<OUTBOUND, void>::value>(),
methodName,
Expand Down Expand Up @@ -1071,6 +1079,10 @@ POP_WARNING()
Register(methodName, implementation);
}

// To reduce the number of possible permutations parameters to the native implementation method are always expected in particular order:
// - context, instance id, property index, json parameters, json result (all optional).
// If index is used then either parameters or result must be present.

private:
template <typename INBOUND, typename OUTBOUND, typename METHOD>
void InternalRegister(const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method)
Expand Down Expand Up @@ -1207,6 +1219,36 @@ POP_WARNING()
});
}

private:
template <typename INBOUND, typename OUTBOUND, typename METHOD> // context+id
void InternalRegister(const ::TemplateIntToType<5>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method)
{
Register(methodName, [method](const Context& context, const string& methodName, const string& /* parameters */, string& /* result */) -> uint32_t {
return (InternalRegisterImpl<METHOD>(method, context, Message::InstanceId(methodName)));
});
}
template <typename INBOUND, typename OUTBOUND, typename METHOD> // context+id+inbound
void InternalRegister(const ::TemplateIntToType<5>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method)
{
Register(methodName, [method](const Context& context, const string& methodName, const string& parameters, string& result) -> uint32_t {
return (InternalRegisterImpl<INBOUND, METHOD>(parameters, result, method, context, Message::InstanceId(methodName)));
});
}
template <typename INBOUND, typename OUTBOUND, typename METHOD> // context+id+outbound
void InternalRegister(const ::TemplateIntToType<5>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method)
{
Register(methodName, [method](const Context& context, const string& methodName, const string&, string& result) -> uint32_t {
return (InternalRegisterImpl<OUTBOUND, METHOD>(result, method, context, Message::InstanceId(methodName)));
});
}
template <typename INBOUND, typename OUTBOUND, typename METHOD> // context+id+inbound+outbound
void InternalRegister(const ::TemplateIntToType<5>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method)
{
Register(methodName, [method](const Context& context, const string& methodName, const string& parameters, string& result) -> uint32_t {
return (InternalRegisterImplIO<INBOUND, OUTBOUND, METHOD>(parameters, result, method, context, Message::InstanceId(methodName)));
});
}

private:
template <typename INBOUND, typename OUTBOUND, typename METHOD> // id+index+inbound
void InternalRegister(const ::TemplateIntToType<6>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method)
Expand All @@ -1230,6 +1272,29 @@ POP_WARNING()
});
}

private:
template <typename INBOUND, typename OUTBOUND, typename METHOD> // context+id+index+inbound
void InternalRegister(const ::TemplateIntToType<7>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method)
{
Register(methodName, [method](const Context& context, const string& methodName, const string& parameters, string& result) -> uint32_t {
return (InternalRegisterImpl<INBOUND, METHOD>(parameters, result, method, context, Message::InstanceId(methodName), Message::Index(methodName)));
});
}
template <typename INBOUND, typename OUTBOUND, typename METHOD> // context+id+index+outbound
void InternalRegister(const ::TemplateIntToType<7>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method)
{
Register(methodName, [method](const Context& context, const string& methodName, const string&, string& result) -> uint32_t {
return (InternalRegisterImpl<OUTBOUND, METHOD>(result, method, context, Message::InstanceId(methodName), Message::Index(methodName)));
});
}
template <typename INBOUND, typename OUTBOUND, typename METHOD> // context+id+index+inbound+outbound
void InternalRegister(const ::TemplateIntToType<7>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method)
{
Register(methodName, [method](const Context& context, const string& methodName, const string& parameters, string& result) -> uint32_t {
return (InternalRegisterImplIO<INBOUND, OUTBOUND, METHOD>(parameters, result, method, context, Message::InstanceId(methodName), Message::Index(methodName)));
});
}

private:
template <typename INBOUND, typename OUTBOUND, typename METHOD, typename REALOBJECT>
void InternalRegister(const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr)
Expand Down
163 changes: 150 additions & 13 deletions Source/plugins/JSONRPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ namespace Thunder {
namespace PluginHost {

namespace {

template<typename JSONRPCERRORASSESSORTYPE>
uint32_t InvokeOnHandler(const Core::JSONRPC::Context& context, const string& method, const string& parameters, string& response, Core::JSONRPC::Handler& handler, JSONRPCERRORASSESSORTYPE errorhandler)
uint32_t InvokeOnHandler(const Core::JSONRPC::Context& context, const string& method, const string& parameters, string& response, Core::JSONRPC::Handler& handler, JSONRPCERRORASSESSORTYPE errorhandler)
{
uint32_t result = handler.Invoke(context, method, parameters, response);
if(result != Core::ERROR_NONE) {
Expand Down Expand Up @@ -460,7 +460,7 @@ namespace PluginHost {
while ((index != _handlers.end()) && (result == nullptr)) {
if (index->HasVersionSupport(version) == true) {
result = &(*index);
}
}
else {
index++;
}
Expand Down Expand Up @@ -509,8 +509,8 @@ namespace PluginHost {
{
_handlers.front().Register<INBOUND, METHOD>(methodName, method);
}
void Register(const string& methodName, const Core::JSONRPC::InvokeFunction& lambda)
{
void Register(const string& methodName, const Core::JSONRPC::InvokeFunction& lambda)
{
_handlers.front().Register(methodName, lambda);
}
void Register(const string& methodName, const Core::JSONRPC::CallbackFunction& lambda)
Expand Down Expand Up @@ -615,7 +615,7 @@ namespace PluginHost {

// Inherited via IDispatcher
// ---------------------------------------------------------------------------------
uint32_t Invoke(const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) override
uint32_t Invoke(const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) override
{
return InvokeHandler(channelId, id, token, method, parameters, response);
}
Expand Down Expand Up @@ -683,7 +683,7 @@ namespace PluginHost {
}
else {
Core::JSONRPC::Handler* handler(Handler(realMethod));

if (handler != nullptr) {
Core::JSONRPC::Context context(channelId, id, token);
result = InvokeOnHandler<JSONRPCERRORASSESSORTYPE>(context, Core::JSONRPC::Message::FullMethod(method), parameters, response, *handler, errorhandler);
Expand Down Expand Up @@ -804,7 +804,7 @@ namespace PluginHost {
std::vector<uint8_t> versions({ version });
_handlers.emplace_front(versions);
index = _handlers.begin();
}
}
index->Register(methodName, Core::JSONRPC::InvokeFunction());

_adminLock.Unlock();
Expand Down Expand Up @@ -1048,7 +1048,7 @@ namespace JSONRPCErrorAssessorTypes {
class EXTERNAL JSONRPCErrorAssessor : public JSONRPC {
public:

JSONRPCErrorAssessor(JSONRPCERRORASSESSORTYPE errorhandler)
JSONRPCErrorAssessor(JSONRPCERRORASSESSORTYPE errorhandler)
: JSONRPC()
, _errorhandler(errorhandler)
{
Expand All @@ -1061,7 +1061,7 @@ namespace JSONRPCErrorAssessorTypes {
JSONRPCErrorAssessor(JSONRPCErrorAssessor&&) = delete;
JSONRPCErrorAssessor &operator=(JSONRPCErrorAssessor&&) = delete;

uint32_t Invoke(const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) override
uint32_t Invoke(const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) override
{
return JSONRPC::InvokeHandler<JSONRPCERRORASSESSORTYPE>(channelId, id, token, method, parameters, response, _errorhandler);
}
Expand All @@ -1075,13 +1075,13 @@ namespace JSONRPCErrorAssessorTypes {
class EXTERNAL JSONRPCErrorAssessor<JSONRPCErrorAssessorTypes::StdFunctionCallbackType> : public JSONRPC {
public:

JSONRPCErrorAssessor(const JSONRPCErrorAssessorTypes::StdFunctionCallbackType& errorhandler)
JSONRPCErrorAssessor(const JSONRPCErrorAssessorTypes::StdFunctionCallbackType& errorhandler)
: JSONRPC()
, _errorhandler(errorhandler)
{
}

JSONRPCErrorAssessor(JSONRPCErrorAssessorTypes::StdFunctionCallbackType&& errorhandler)
JSONRPCErrorAssessor(JSONRPCErrorAssessorTypes::StdFunctionCallbackType&& errorhandler)
: JSONRPC()
, _errorhandler(std::move(errorhandler))
{
Expand All @@ -1094,7 +1094,7 @@ namespace JSONRPCErrorAssessorTypes {
JSONRPCErrorAssessor(JSONRPCErrorAssessor&&) = delete;
JSONRPCErrorAssessor &operator=(JSONRPCErrorAssessor&&) = delete;

uint32_t Invoke(const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) override
uint32_t Invoke(const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) override
{
return JSONRPC::InvokeHandler<const JSONRPCErrorAssessorTypes::StdFunctionCallbackType&>(channelId, id, token, method, parameters, response, _errorhandler);
}
Expand All @@ -1106,6 +1106,143 @@ namespace JSONRPCErrorAssessorTypes {

#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__

template<typename T, typename ID>
class LookupStorageType {
public:
LookupStorageType()
: _lock()
, _storage()
, _nextId(1)
{
}
~LookupStorageType() = default;

LookupStorageType(const LookupStorageType&) = delete;
LookupStorageType(LookupStorageType&&) = delete;
LookupStorageType& operator=(const LookupStorageType&) = delete;
LookupStorageType& operator=(LookupStorageType&&) = delete;

public:
uint32_t Store(T* obj, const Core::JSONRPC::Context& context)
{
ID id = 0;

ASSERT(obj != nullptr);

if (obj != nullptr) {

obj->AddRef();

_lock.Lock();

id = _nextId++;

_storage.emplace(std::piecewise_construct,
std::forward_as_tuple(id),
std::forward_as_tuple(context.ChannelId(), obj));

_lock.Unlock();
}

return (id);
}

T* Lookup(const Core::JSONRPC::Context& context, const ID id)
{
T* obj{};

_lock.Lock();

auto it = _storage.find(id);

if ((it != _storage.end()) && ((*it).second.first == context.ChannelId())) {
obj = (*it).second.second;
obj->AddRef();
}

_lock.Unlock();

return (obj);
}

const T* Lookup(const Core::JSONRPC::Context& context, const ID id) const
{
const T* obj{};

_lock.Lock();

auto const it = _storage.cfind(id);

if ((it != _storage.cend()) && ((*it).second.first == context.ChannelId())) {
obj = (*it).second.second;
obj->AddRef();
}

_lock.Unlock();

return (obj);
}

T* Dispose(const Core::JSONRPC::Context& context, const ID id)
{
T* obj{};

_lock.Lock();

auto it = _storage.find(id);

if (it != _storage.end() && ((*it).second.first == context.ChannelId())) {
obj = (*it).second.second;
_storage.erase(it);
}

_lock.Unlock();

return (obj);
}

public:
using OnCloseCallback = std::function<void(const ID, const uint32_t, T*)>;

void Closed(const uint32_t channel, const OnCloseCallback& callback = nullptr)
{
_lock.Lock();

auto it = _storage.begin();

while (it != _storage.end()) {
if ((*it).second.first == channel) {

T* obj = (*it).second.second;
ASSERT(obj != nullptr);

if (callback) {
callback((*it).first, T::ID, obj);
}

obj->Release();
it = _storage.erase(it);
}
else {
++it;
}
}

_lock.Unlock();

}

void Closed(const Core::JSONRPC::Context& context, const OnCloseCallback& callback = nullptr)
{
Closed(context.ChannelId(), callback);
}

private:
mutable Core::CriticalSection _lock;
std::map<ID, std::pair<uint32_t, T*>> _storage;
ID _nextId;
};

} // namespace Thunder::PluginHost
}

0 comments on commit bc58299

Please sign in to comment.