diff --git a/CHANGELOG.md b/CHANGELOG.md index 3056ea2a..3f73a4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# [3.0.0-next.9](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.8...v3.0.0-next.9) (2024-07-29) + + +### Bug Fixes + +* Added CPP Event prioritization ([#197](https://github.com/rdkcentral/firebolt-openrpc/issues/197)) ([11d25e9](https://github.com/rdkcentral/firebolt-openrpc/commit/11d25e9a9784cea105c1de832179e776956b893a)) + +# [3.0.0-next.8](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.7...v3.0.0-next.8) (2024-07-29) + + +### Bug Fixes + +* Added firebolt header to the call-metrics ([#201](https://github.com/rdkcentral/firebolt-openrpc/issues/201)) ([1b3f261](https://github.com/rdkcentral/firebolt-openrpc/commit/1b3f2619c8da9d560b37e48dc5ca78709b453d6e)) + # [3.0.0-next.7](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.6...v3.0.0-next.7) (2024-07-10) diff --git a/languages/cpp/src/shared/src/Event/Event.cpp b/languages/cpp/src/shared/src/Event/Event.cpp index 5d739d70..6f771462 100644 --- a/languages/cpp/src/shared/src/Event/Event.cpp +++ b/languages/cpp/src/shared/src/Event/Event.cpp @@ -22,7 +22,8 @@ namespace FireboltSDK { Event* Event::_singleton = nullptr; Event::Event() - : _eventMap() + : _internalEventMap() + , _externalEventMap() , _adminLock() , _transport(nullptr) { @@ -87,77 +88,111 @@ namespace FireboltSDK { } return result; } - + + + /* This function combines both internal and external event maps, and iterates over them to find the specified event. + If the event is found, it iterates over its associated callbacks, updating their states and executing them if applicable. + Callbacks in the REVOKED state are removed. + */ Firebolt::Error Event::Dispatch(const string& eventName, const WPEFramework::Core::ProxyType& jsonResponse) /* override */ { string response = jsonResponse->Result.Value(); - _adminLock.Lock(); - EventMap::iterator eventIndex = _eventMap.find(eventName); - if (eventIndex != _eventMap.end()) { - CallbackMap::iterator callbackIndex = eventIndex->second.begin(); - while(callbackIndex != eventIndex->second.end()) { - State state; - if (callbackIndex->second.state != State::REVOKED) { - callbackIndex->second.state = State::EXECUTING; - } - state = callbackIndex->second.state; - _adminLock.Unlock(); - if (state == State::EXECUTING) { - callbackIndex->second.lambda(callbackIndex->first, callbackIndex->second.userdata, (jsonResponse->Result.Value())); - } - _adminLock.Lock(); - if (callbackIndex->second.state == State::REVOKED) { - callbackIndex = eventIndex->second.erase(callbackIndex); - if (eventIndex->second.size() == 0) { - _eventMap.erase(eventIndex); + std::vector eventMaps = {&_internalEventMap, &_externalEventMap}; + + // Combine both _internalEventMap and _externalEventMap into a single loop + for (auto eventMap : eventMaps) { + _adminLock.Lock(); + EventMap::iterator eventIndex = eventMap->find(eventName); + if (eventIndex != eventMap->end()) { + CallbackMap& callbacks = eventIndex->second; + for (CallbackMap::iterator callbackIndex = callbacks.begin(); callbackIndex != callbacks.end();) { + State state; + if (callbackIndex->second.state != State::REVOKED) { + callbackIndex->second.state = State::EXECUTING; + } + state = callbackIndex->second.state; + _adminLock.Unlock(); + if (state == State::EXECUTING) { + callbackIndex->second.lambda(callbackIndex->first, callbackIndex->second.userdata, response); + } + _adminLock.Lock(); + if (callbackIndex->second.state == State::REVOKED) { + callbackIndex = callbacks.erase(callbackIndex); + if (callbacks.empty()) { + eventMap->erase(eventIndex); // Erase from the correct eventMap + break; // No need to continue iterating if map is empty + } + } else { + callbackIndex->second.state = State::IDLE; + ++callbackIndex; } - } else { - callbackIndex->second.state = State::IDLE; - callbackIndex++; } } + _adminLock.Unlock(); } - _adminLock.Unlock(); - - return Firebolt::Error::None;; + return Firebolt::Error::None; } + Firebolt::Error Event::Revoke(const string& eventName, void* usercb) { Firebolt::Error status = Firebolt::Error::None; - _adminLock.Lock(); - EventMap::iterator eventIndex = _eventMap.begin(); - if (eventIndex != _eventMap.end()) { - CallbackMap::iterator callbackIndex = eventIndex->second.find(usercb); - if (callbackIndex->second.state != State::EXECUTING) { + + // Combine both _internalEventMap and _externalEventMap into a single loop + std::vector eventMaps = {&_internalEventMap, &_externalEventMap}; + + for (auto eventMap : eventMaps) { + _adminLock.Lock(); // Lock inside the loop + + // Find the eventIndex for eventName in the current eventMap + EventMap::iterator eventIndex = eventMap->find(eventName); + if (eventIndex != eventMap->end()) { + // Find the callbackIndex for usercb in the current CallbackMap + CallbackMap::iterator callbackIndex = eventIndex->second.find(usercb); if (callbackIndex != eventIndex->second.end()) { - eventIndex->second.erase(callbackIndex); + // Check if callback is not executing, then erase it + if (callbackIndex->second.state != State::EXECUTING) { + eventIndex->second.erase(callbackIndex); + } else { + // Mark the callback as revoked + callbackIndex->second.state = State::REVOKED; + } + + // Check if the CallbackMap is empty after potential erasure + if (eventIndex->second.empty()) { + eventMap->erase(eventIndex); + } else { + // Set status to General error if CallbackMap is not empty + status = Firebolt::Error::General; + } } - } else { - callbackIndex->second.state = State::REVOKED; - } - if (eventIndex->second.size() == 0) { - _eventMap.erase(eventIndex); - } else { - status = Firebolt::Error::General; } + + _adminLock.Unlock(); // Unlock after processing each eventMap } - _adminLock.Unlock(); return status; } void Event::Clear() { - EventMap::iterator eventIndex = _eventMap.begin(); - while (eventIndex != _eventMap.end()) { - CallbackMap::iterator callbackIndex = eventIndex->second.begin(); - while (callbackIndex != eventIndex->second.end()) { - callbackIndex = eventIndex->second.erase(callbackIndex); + // Clear both _internalEventMap and _externalEventMap + std::vector eventMaps = {&_internalEventMap, &_externalEventMap}; + + for (auto eventMap : eventMaps) { + _adminLock.Lock(); // Lock before clearing + + EventMap::iterator eventIndex = eventMap->begin(); + while (eventIndex != eventMap->end()) { + CallbackMap::iterator callbackIndex = eventIndex->second.begin(); + while (callbackIndex != eventIndex->second.end()) { + callbackIndex = eventIndex->second.erase(callbackIndex); + } + eventIndex = eventMap->erase(eventIndex); } - eventIndex = _eventMap.erase(eventIndex); + + _adminLock.Unlock(); // Unlock after clearing } - _adminLock.Unlock(); } -} +} \ No newline at end of file diff --git a/languages/cpp/src/shared/src/Event/Event.h b/languages/cpp/src/shared/src/Event/Event.h index 7299fde0..6e599716 100644 --- a/languages/cpp/src/shared/src/Event/Event.h +++ b/languages/cpp/src/shared/src/Event/Event.h @@ -80,44 +80,55 @@ namespace FireboltSDK { } template - Firebolt::Error Subscribe(const string& eventName, JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata) + Firebolt::Error Subscribe(const string& eventName, JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata, bool prioritize = false) { Firebolt::Error status = Firebolt::Error::General; + if (_transport != nullptr) { + EventMap& eventMap = prioritize ? _internalEventMap : _externalEventMap; + + status = Assign(eventMap, eventName, callback, usercb, userdata); - status = Assign(eventName, callback, usercb, userdata); if (status == Firebolt::Error::None) { Response response; - WPEFramework::Core::JSON::Variant Listen = true; jsonParameters.Set(_T("listen"), Listen); string parameters; jsonParameters.ToString(parameters); - status = _transport->Subscribe(eventName, parameters, response); + status = _transport->Subscribe(eventName, parameters, response, prioritize); if (status != Firebolt::Error::None) { Revoke(eventName, usercb); - } else if ((response.Listening.IsSet() == true) && - (response.Listening.Value() == true)) { + } else if (response.Listening.IsSet() && response.Listening.Value()) { status = Firebolt::Error::None; } } } + return status; + } + // To prioritize internal and external events and its corresponding callbacks + template + Firebolt::Error Prioritize(const string& eventName,JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata) + { + Firebolt::Error status = Firebolt::Error::General; + // Assuming prioritized events also need subscription via transport + status = Subscribe(eventName, jsonParameters, callback, usercb, userdata, true); return status; } + Firebolt::Error Unsubscribe(const string& eventName, void* usercb); private: template - Firebolt::Error Assign(const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata) + Firebolt::Error Assign(EventMap& eventMap, const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata) { + Firebolt::Error status = Firebolt::Error::General; std::function actualCallback = callback; DispatchFunction implementation = [actualCallback](void* usercb, const void* userdata, const string& parameters) -> Firebolt::Error { - WPEFramework::Core::ProxyType* inbound = new WPEFramework::Core::ProxyType(); *inbound = WPEFramework::Core::ProxyType::Create(); (*inbound)->FromString(parameters); @@ -125,12 +136,13 @@ namespace FireboltSDK { return (Firebolt::Error::None); }; CallbackData callbackData = {implementation, userdata, State::IDLE}; - _adminLock.Lock(); - EventMap::iterator eventIndex = _eventMap.find(eventName); - if (eventIndex != _eventMap.end()) { + EventMap::iterator eventIndex = eventMap.find(eventName); + if (eventIndex != eventMap.end()) { CallbackMap::iterator callbackIndex = eventIndex->second.find(usercb); + if (callbackIndex == eventIndex->second.end()) { + std::cout << "Registering new callback for event: " << eventName << std::endl; eventIndex->second.emplace(std::piecewise_construct, std::forward_as_tuple(usercb), std::forward_as_tuple(callbackData)); status = Firebolt::Error::None; } @@ -138,7 +150,7 @@ namespace FireboltSDK { CallbackMap callbackMap; callbackMap.emplace(std::piecewise_construct, std::forward_as_tuple(usercb), std::forward_as_tuple(callbackData)); - _eventMap.emplace(std::piecewise_construct, std::forward_as_tuple(eventName), std::forward_as_tuple(callbackMap)); + eventMap.emplace(std::piecewise_construct, std::forward_as_tuple(eventName), std::forward_as_tuple(callbackMap)); status = Firebolt::Error::None; } @@ -153,11 +165,12 @@ namespace FireboltSDK { Firebolt::Error ValidateResponse(const WPEFramework::Core::ProxyType& jsonResponse, bool& enabled) override; Firebolt::Error Dispatch(const string& eventName, const WPEFramework::Core::ProxyType& jsonResponse) override; - private: - EventMap _eventMap; + private: + EventMap _internalEventMap; + EventMap _externalEventMap; WPEFramework::Core::CriticalSection _adminLock; Transport* _transport; static Event* _singleton; }; -} +} \ No newline at end of file diff --git a/languages/cpp/src/shared/src/Transport/Transport.h b/languages/cpp/src/shared/src/Transport/Transport.h index 0caa7603..16205745 100644 --- a/languages/cpp/src/shared/src/Transport/Transport.h +++ b/languages/cpp/src/shared/src/Transport/Transport.h @@ -565,7 +565,13 @@ namespace FireboltSDK { void Revoke(const string& eventName) { _adminLock.Lock(); - _eventMap.erase(eventName); + + // Remove from internal event map + _internalEventMap.erase(eventName); + + // Remove from external event map + _externalEventMap.erase(eventName); + _adminLock.Unlock(); } @@ -640,22 +646,31 @@ namespace FireboltSDK { } template - Firebolt::Error Subscribe(const string& eventName, const string& parameters, RESPONSE& response) + + Firebolt::Error Subscribe(const string& eventName, const string& parameters, RESPONSE& response, bool updateInternal = false) { Entry slot; uint32_t id = _channel->Sequence(); Firebolt::Error result = Send(eventName, parameters, id); + if (result == Firebolt::Error::None) { _adminLock.Lock(); - _eventMap.emplace(std::piecewise_construct, - std::forward_as_tuple(eventName), - std::forward_as_tuple(~0)); + + // Choose the map based on updateInternal flag + EventMap& eventMap = updateInternal ? _internalEventMap : _externalEventMap; + + // Add to the selected event map + eventMap.emplace(std::piecewise_construct, + std::forward_as_tuple(eventName), + std::forward_as_tuple(id)); + _adminLock.Unlock(); - result = WaitForEventResponse(id, eventName, response, _waitTime); + result = WaitForEventResponse(id, eventName, response, _waitTime, eventMap); + } - return (result); + return result; } Firebolt::Error Unsubscribe(const string& eventName, const string& parameters) @@ -692,18 +707,34 @@ namespace FireboltSDK { private: friend Channel; + inline bool IsEvent(const uint32_t id, string& eventName) { _adminLock.Lock(); - for (auto& event : _eventMap) { - if (event.second == id) { - eventName = event.first; - break; + + bool eventExist = false; + + // List of maps to search + std::vector maps = {&_internalEventMap, &_externalEventMap}; + + // Loop through each map + for (const auto* map : maps) { + for (const auto& event : *map) { + if (event.second == id) { + eventName = event.first; + eventExist = true; + break; // Break the inner loop + } + } + if (eventExist) { + break; // Break the outer loop } } + _adminLock.Unlock(); - return (eventName.empty() != true); + return eventExist; } + uint64_t Timed() { uint64_t result = ~0; @@ -802,8 +833,7 @@ namespace FireboltSDK { return (result); } - - + template Firebolt::Error Send(const string& method, const PARAMETERS& parameters, const uint32_t& id) { @@ -844,7 +874,7 @@ namespace FireboltSDK { static constexpr uint32_t WAITSLOT_TIME = 100; template - Firebolt::Error WaitForEventResponse(const uint32_t& id, const string& eventName, RESPONSE& response, const uint32_t waitTime) + Firebolt::Error WaitForEventResponse(const uint32_t& id, const string& eventName, RESPONSE& response, const uint32_t waitTime, EventMap& _eventMap) { Firebolt::Error result = Firebolt::Error::Timedout; _adminLock.Lock(); @@ -973,7 +1003,8 @@ namespace FireboltSDK { WPEFramework::Core::ProxyType _channel; IEventHandler* _eventHandler; PendingMap _pendingQueue; - EventMap _eventMap; + EventMap _internalEventMap; + EventMap _externalEventMap; uint64_t _scheduledTime; uint32_t _waitTime; Listener _listener; diff --git a/languages/cpp/templates/imports/calls-metrics.impl b/languages/cpp/templates/imports/calls-metrics.impl index 75fd87c6..693dc63a 100644 --- a/languages/cpp/templates/imports/calls-metrics.impl +++ b/languages/cpp/templates/imports/calls-metrics.impl @@ -1 +1,2 @@ -#include "metrics_impl.h" +#include "firebolt.h" + diff --git a/languages/cpp/templates/methods/calls-metrics.cpp b/languages/cpp/templates/methods/calls-metrics.cpp index 1b6765c6..9c508c55 100644 --- a/languages/cpp/templates/methods/calls-metrics.cpp +++ b/languages/cpp/templates/methods/calls-metrics.cpp @@ -1,6 +1,7 @@ /* ${method.name} - ${method.description} */ - static void ${method.name}Dispatcher(const void* result) { - Metrics::MetricsImpl::${method.name}(${if.result.nonboolean}${if.result.nonvoid}(static_cast<${method.result.json.type}>(const_cast(result)))${end.if.result.nonvoid}${end.if.result.nonboolean}); + static void ${method.name}Dispatcher(const void* result) { + // Accessing Metrics methods using singleton Instance + Firebolt::IFireboltAccessor::Instance().MetricsInterface().${method.name}(${if.result.nonboolean}${if.result.nonvoid}(static_cast<${method.result.json.type}>(const_cast(result)))${end.if.result.nonvoid}${end.if.result.nonboolean}); } /* ${method.name} - ${method.description} */ ${method.signature.result} ${info.Title}Impl::${method.name}( ${method.signature.params}${if.params}, ${end.if.params}Firebolt::Error *err ) ${if.result.nonvoid}${if.params.empty} const${end.if.params.empty}${end.if.result.nonvoid} diff --git a/package-lock.json b/package-lock.json index 609f6d05..6034625b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@firebolt-js/openrpc", - "version": "3.0.0-next.7", + "version": "3.0.0-next.9", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@firebolt-js/openrpc", - "version": "3.0.0-next.7", + "version": "3.0.0-next.9", "license": "Apache-2.0", "dependencies": { "ajv": "^8.12.0", diff --git a/package.json b/package.json index dc7ade1b..6fdf60b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@firebolt-js/openrpc", - "version": "3.0.0-next.7", + "version": "3.0.0-next.9", "description": "The Firebolt SDK Code & Doc Generator", "main": "languages/javascript/src/sdk.mjs", "type": "module", diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index 969d47a1..aedcc4e9 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -601,7 +601,7 @@ const insertAggregateMacros = (fContents = '', aggregateMacros = {}) => { fContents = fContents.replace(/[ \t]*\/\* \$\{MOCK_OBJECTS\} \*\/[ \t]*\n/, aggregateMacros.mockObjects) fContents = fContents.replace(/\$\{readable\}/g, aggregateMacros.version.readable) fContents = fContents.replace(/\$\{package.name\}/g, aggregateMacros.library) - + return fContents } diff --git a/src/macrofier/index.mjs b/src/macrofier/index.mjs index 298241f6..9ff30291 100644 --- a/src/macrofier/index.mjs +++ b/src/macrofier/index.mjs @@ -196,14 +196,14 @@ const macrofy = async ( templatesPerModule.forEach(t => { const macros = engine.generateMacros(module, templates, exampleTemplates, {hideExcluded: hideExcluded, copySchemasIntoModules: copySchemasIntoModules, createPolymorphicMethods: createPolymorphicMethods, destination: t, type: 'methods'}) let content = getTemplateForModule(module.info.title, t, templates) - + // NOTE: whichever insert is called first also needs to be called again last, so each phase can insert recursive macros from the other content = engine.insertAggregateMacros(content, aggregateMacros) content = engine.insertMacros(content, macros) content = engine.insertAggregateMacros(content, aggregateMacros) const location = createModuleDirectories ? path.join(output, module.info.title, t) : path.join(output, t.replace(/module/, module.info.title.toLowerCase()).replace(/index/, module.info.title)) - + outputFiles[location] = content logSuccess(`Generated macros for module ${path.relative(output, location)}`) })