From 5c6afdf1b7038dd81a6aeb538df41cc4212ec2f0 Mon Sep 17 00:00:00 2001 From: MFransen69 <39826971+MFransen69@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:04:21 +0200 Subject: [PATCH] [JSONRPC] Dynamic error messages (#1782) * [JSONRPC] Dynamic error messages * [JSONRPC] improved dynamic error handling * [JSONRPC] improved dynamic error support * [JSONRPC] can of course be const * [JSONRPC] add errorcode to dynamic error message callback --- Source/CMakeLists.txt | 8 +++ Source/core/JSON.cpp | 6 ++ Source/core/JSON.h | 8 +++ Source/plugins/JSONRPC.h | 119 +++++++++++++++++++++++++++++++-- Source/websocket/JSONRPCLink.h | 10 +++ cmake/project.cmake.in | 5 ++ 6 files changed, 149 insertions(+), 7 deletions(-) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 410ffe7dc3..1ce83c3921 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -45,6 +45,9 @@ option(EXCEPTION_CATCHING "Enable unhandled exception handling catching." OFF) option(DEADLOCK_DETECTION "Enable deadlock detection tooling." OFF) +option(DISABLE_USE_COMPLEMENTARY_CODE_SET + "Disable the complementary code set" OFF) + if(HIDE_NON_EXTERNAL_SYMBOLS) set(CMAKE_CXX_VISIBILITY_PRESET hidden) @@ -84,6 +87,11 @@ else() endif() endif() +if(DISABLE_USE_COMPLEMENTARY_CODE_SET) + add_definitions(-D__DISABLE_USE_COMPLEMENTARY_CODE_SET__) + message(STATUS "complementary code set disabled") +endif() + if(CORE) add_subdirectory(core) endif() diff --git a/Source/core/JSON.cpp b/Source/core/JSON.cpp index 469ba90502..d76c705d2e 100644 --- a/Source/core/JSON.cpp +++ b/Source/core/JSON.cpp @@ -41,6 +41,8 @@ namespace Core { /* static */ char IElement::TrueTag[5] = { 't', 'r', 'u', 'e', '\0' }; /* static */ char IElement::FalseTag[6] = { 'f', 'a', 'l', 's', 'e', '\0' }; +#ifndef __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + string Variant::GetDebugString(const TCHAR name[], int indent, int arrayIndex) const { std::stringstream ss; @@ -78,6 +80,10 @@ namespace Core { ss << iterator.Current().GetDebugString(iterator.Label(), indent); return ss.str(); } + +#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + + } } diff --git a/Source/core/JSON.h b/Source/core/JSON.h index d59bfe5c29..bb7e7df5fa 100644 --- a/Source/core/JSON.h +++ b/Source/core/JSON.h @@ -4192,6 +4192,8 @@ namespace Core { mutable String _fieldName; }; +#ifndef __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + class VariantContainer; class EXTERNAL Variant : public JSON::String { @@ -5089,12 +5091,18 @@ namespace Core { } }; +#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + } // namespace JSON } // namespace Core } // namespace Thunder +#ifndef __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + using JsonObject = Thunder::Core::JSON::VariantContainer; using JsonValue = Thunder::Core::JSON::Variant; using JsonArray = Thunder::Core::JSON::ArrayType; +#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + #endif // __JSON_H diff --git a/Source/plugins/JSONRPC.h b/Source/plugins/JSONRPC.h index e10169457d..b08dc7d29d 100644 --- a/Source/plugins/JSONRPC.h +++ b/Source/plugins/JSONRPC.h @@ -29,6 +29,27 @@ 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 result = handler.Invoke(context, method, parameters, response); + if(result != Core::ERROR_NONE) { + result = errorhandler(context, method, parameters, result, response); + } + + return result; + } + + template<> + uint32_t InvokeOnHandler(const Core::JSONRPC::Context& context, const string& method, const string& parameters, string& response, Core::JSONRPC::Handler& handler, void*) + { + return handler.Invoke(context, method, parameters, response); + } + + } + class EXTERNAL JSONRPC : public IDispatcher { public: using SendIfMethod = std::function; @@ -448,6 +469,7 @@ namespace PluginHost { return (result); } + // // Register/Unregister methods for incoming method handling on the "base" handler elements. // ------------------------------------------------------------------------------------------------------------------------------ @@ -456,11 +478,17 @@ namespace PluginHost { { _handlers.front().Property(methodName, getter, setter, objectPtr); } + +#ifndef __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + template void Register(const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { _handlers.front().Register(methodName, method, objectPtr); } + +#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + template void Register(const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { @@ -587,7 +615,13 @@ 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); + } + + template + uint32_t InvokeHandler(const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response, JSONRPCERRORASSESSORTYPE errorhandler = nullptr) { uint32_t result = Core::ERROR_PARSE_FAILURE; if (method.empty() == false) { @@ -649,13 +683,12 @@ namespace PluginHost { } else { Core::JSONRPC::Handler* handler(Handler(realMethod)); - - if (handler == nullptr) { - result = Core::ERROR_INCORRECT_URL; - } - else { + + if (handler != nullptr) { Core::JSONRPC::Context context(channelId, id, token); - result = handler->Invoke(context, Core::JSONRPC::Message::FullMethod(method), parameters, response); + result = InvokeOnHandler(context, Core::JSONRPC::Message::FullMethod(method), parameters, response, *handler, errorhandler); + } else { + result = Core::ERROR_INCORRECT_URL; } } } @@ -663,6 +696,7 @@ namespace PluginHost { return (result); } + Core::hresult Subscribe(ICallback* callback, const string& eventId, const string& designator) override { uint32_t result; @@ -1002,5 +1036,76 @@ namespace PluginHost { StatusCallbackMap _observers; }; +#ifndef __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + +namespace JSONRPCErrorAssessorTypes { + + using FunctionCallbackType = uint32_t (*) (const Core::JSONRPC::Context&, const string&, const string&, const uint32_t errorcode, string&); + using StdFunctionCallbackType = std::function; +} + + template + class EXTERNAL JSONRPCErrorAssessor : public JSONRPC { + public: + + JSONRPCErrorAssessor(JSONRPCERRORASSESSORTYPE errorhandler) + : JSONRPC() + , _errorhandler(errorhandler) + { + } + + ~JSONRPCErrorAssessor() override = default; + + JSONRPCErrorAssessor(const JSONRPCErrorAssessor&) = delete; + JSONRPCErrorAssessor &operator=(const JSONRPCErrorAssessor&) = delete; + 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 + { + return JSONRPC::InvokeHandler(channelId, id, token, method, parameters, response, _errorhandler); + } + + + private: + JSONRPCERRORASSESSORTYPE _errorhandler; + }; + + template<> + class EXTERNAL JSONRPCErrorAssessor : public JSONRPC { + public: + + JSONRPCErrorAssessor(const JSONRPCErrorAssessorTypes::StdFunctionCallbackType& errorhandler) + : JSONRPC() + , _errorhandler(errorhandler) + { + } + + JSONRPCErrorAssessor(JSONRPCErrorAssessorTypes::StdFunctionCallbackType&& errorhandler) + : JSONRPC() + , _errorhandler(std::move(errorhandler)) + { + } + + ~JSONRPCErrorAssessor() override = default; + + JSONRPCErrorAssessor(const JSONRPCErrorAssessor&) = delete; + JSONRPCErrorAssessor &operator=(const JSONRPCErrorAssessor&) = delete; + 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 + { + return JSONRPC::InvokeHandler(channelId, id, token, method, parameters, response, _errorhandler); + } + + + private: + JSONRPCErrorAssessorTypes::StdFunctionCallbackType _errorhandler; + }; + +#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + } // namespace Thunder::PluginHost } + diff --git a/Source/websocket/JSONRPCLink.h b/Source/websocket/JSONRPCLink.h index b7eefd241c..be0fa3c128 100644 --- a/Source/websocket/JSONRPCLink.h +++ b/Source/websocket/JSONRPCLink.h @@ -752,6 +752,8 @@ namespace Thunder { return (Send(waitTime, method, parameters, response)); } +#ifndef __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + // Generic JSONRPC methods. // Anything goes! // these objects have no type chacking, will consume more memory and processing takes more time @@ -784,6 +786,8 @@ namespace Thunder { return InternalInvoke(waitTime, method, parameters, inbound); } +#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + private: friend CommunicationChannel; @@ -1452,6 +1456,8 @@ namespace Thunder { return (_connection.Invoke(waitTime, method, parameters, response)); } +#ifndef __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + // Opaque JSON structure methods. // Anything goes! // =================================================================================== @@ -1467,6 +1473,10 @@ namespace Thunder { { return (_connection.template Get(waitTime, method, object)); } + +#endif // __DISABLE_USE_COMPLEMENTARY_CODE_SET__ + + bool IsActivated() { return (_connection.IsActivated()); diff --git a/cmake/project.cmake.in b/cmake/project.cmake.in index e0e636b902..b50c42dc9e 100644 --- a/cmake/project.cmake.in +++ b/cmake/project.cmake.in @@ -95,6 +95,11 @@ if(VERSIONED_LIBRARY_LOADING) add_definitions(-DVERSIONED_LIBRARY_LOADING) endif() +set(DISABLE_USE_COMPLEMENTARY_CODE_SET @DISABLE_USE_COMPLEMENTARY_CODE_SET@) +if(DISABLE_USE_COMPLEMENTARY_CODE_SET) + add_definitions(-D__DISABLE_USE_COMPLEMENTARY_CODE_SET__) +endif() + set(CMAKE_BUILD_TYPE @CMAKE_BUILD_TYPE@ CACHE INTERNAL "" FORCE) # FIX_ME: Disable fortify source.