From bc58299757fb06bd5291687502a94928925f6f15 Mon Sep 17 00:00:00 2001 From: sebaszm <45654185+sebaszm@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:45:00 +0100 Subject: [PATCH] Facilitate automatic JSON-RPC object lookup (#1808) * Facilitate automatic JSON-RPC object lookup * Lock resources * fix clang warning --------- Co-authored-by: Pierre Wielders --- Source/core/JSONRPC.h | 69 ++++++++++++++++- Source/plugins/JSONRPC.h | 163 +++++++++++++++++++++++++++++++++++---- 2 files changed, 217 insertions(+), 15 deletions(-) diff --git a/Source/core/JSONRPC.h b/Source/core/JSONRPC.h index 9089e274d..2eb061e9a 100644 --- a/Source/core/JSONRPC.h +++ b/Source/core/JSONRPC.h @@ -820,9 +820,13 @@ POP_WARNING() { using ARG0 = typename std::decay::template argument<0>::type>::type; using ARG1 = typename std::decay::template argument<1>::type>::type; + using ARG2 = typename std::decay::template argument<2>::type>::type; + constexpr auto HAS_CONTEXT = std::is_same::value; + constexpr auto HAS_INDEX = (std::is_same::value | std::is_same::value | std::is_same::value); + constexpr auto HAS_INSTANCEID = (std::is_same::value | std::is_same::value); InternalRegister( - ::TemplateIntToType::value | (std::is_same::value << 1) | (std::is_same::value << 1) | (std::is_same::value << 2)>(), + ::TemplateIntToType(), ::TemplateIntToType::value>(), ::TemplateIntToType::value>(), methodName, @@ -833,9 +837,13 @@ POP_WARNING() { using ARG0 = typename std::decay::template argument<0>::type>::type; using ARG1 = typename std::decay::template argument<1>::type>::type; + using ARG2 = typename std::decay::template argument<2>::type>::type; + constexpr auto HAS_CONTEXT = std::is_same::value; + constexpr auto HAS_INDEX = (std::is_same::value | std::is_same::value | std::is_same::value); + constexpr auto HAS_INSTANCEID = (std::is_same::value | std::is_same::value); InternalRegister( - ::TemplateIntToType::value | (std::is_same::value << 1) | (std::is_same::value << 1) | (std::is_same::value << 2)>(), + ::TemplateIntToType(), ::TemplateIntToType::value>(), ::TemplateIntToType::value>(), methodName, @@ -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 void InternalRegister(const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method) @@ -1207,6 +1219,36 @@ POP_WARNING() }); } + private: + template // 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, context, Message::InstanceId(methodName))); + }); + } + template // 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(parameters, result, method, context, Message::InstanceId(methodName))); + }); + } + template // 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(result, method, context, Message::InstanceId(methodName))); + }); + } + template // 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(parameters, result, method, context, Message::InstanceId(methodName))); + }); + } + private: template // id+index+inbound void InternalRegister(const ::TemplateIntToType<6>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method) @@ -1230,6 +1272,29 @@ POP_WARNING() }); } + private: + template // 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(parameters, result, method, context, Message::InstanceId(methodName), Message::Index(methodName))); + }); + } + template // 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(result, method, context, Message::InstanceId(methodName), Message::Index(methodName))); + }); + } + template // 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(parameters, result, method, context, Message::InstanceId(methodName), Message::Index(methodName))); + }); + } + private: template void InternalRegister(const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) diff --git a/Source/plugins/JSONRPC.h b/Source/plugins/JSONRPC.h index b08dc7d29..ed7a888b3 100644 --- a/Source/plugins/JSONRPC.h +++ b/Source/plugins/JSONRPC.h @@ -30,9 +30,9 @@ namespace Thunder { namespace PluginHost { namespace { - + template - 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) { @@ -460,7 +460,7 @@ namespace PluginHost { while ((index != _handlers.end()) && (result == nullptr)) { if (index->HasVersionSupport(version) == true) { result = &(*index); - } + } else { index++; } @@ -509,8 +509,8 @@ namespace PluginHost { { _handlers.front().Register(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) @@ -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); } @@ -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(context, Core::JSONRPC::Message::FullMethod(method), parameters, response, *handler, errorhandler); @@ -804,7 +804,7 @@ namespace PluginHost { std::vector versions({ version }); _handlers.emplace_front(versions); index = _handlers.begin(); - } + } index->Register(methodName, Core::JSONRPC::InvokeFunction()); _adminLock.Unlock(); @@ -1048,7 +1048,7 @@ namespace JSONRPCErrorAssessorTypes { class EXTERNAL JSONRPCErrorAssessor : public JSONRPC { public: - JSONRPCErrorAssessor(JSONRPCERRORASSESSORTYPE errorhandler) + JSONRPCErrorAssessor(JSONRPCERRORASSESSORTYPE errorhandler) : JSONRPC() , _errorhandler(errorhandler) { @@ -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(channelId, id, token, method, parameters, response, _errorhandler); } @@ -1075,13 +1075,13 @@ namespace JSONRPCErrorAssessorTypes { class EXTERNAL JSONRPCErrorAssessor : 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)) { @@ -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(channelId, id, token, method, parameters, response, _errorhandler); } @@ -1106,6 +1106,143 @@ namespace JSONRPCErrorAssessorTypes { #endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + template + 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 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> _storage; + ID _nextId; + }; + } // namespace Thunder::PluginHost }