diff --git a/languages/cpp/src/shared/CMakeLists.txt b/languages/cpp/src/shared/CMakeLists.txt index abe84d0e..fd566a3d 100644 --- a/languages/cpp/src/shared/CMakeLists.txt +++ b/languages/cpp/src/shared/CMakeLists.txt @@ -24,11 +24,16 @@ set(FIREBOLT_LOGLEVEL "Info" CACHE STRING "Log level to be enabled") # Default options option(FIREBOLT_ENABLE_STATIC_LIB "Create Firebolt library as Static library" OFF) +option(ENABLE_BIDRECTIONAL "Enable bidirectional communication over WS" OFF) option(ENABLE_TESTS "Build openrpc native test" ON) option(ENABLE_UNIT_TESTS "Enable unit test" ON) option(ENABLE_COVERAGE "Enable code coverage build." ON) option(FIREBOLT_PLAIN_LOG "Disable log coloring" OFF) +if (ENABLE_BIDRECTIONAL) + add_compile_definitions(GATEWAY_BIDIRECTIONAL) +endif () + if (FIREBOLT_PLAIN_LOG) add_compile_definitions(LOGGER_NO_COLOR) endif () @@ -123,4 +128,4 @@ endif() # make sure others can make use cmake settings of Firebolt OpenRPC configure_file( "${CMAKE_SOURCE_DIR}/cmake/project.cmake.in" "${CMAKE_BINARY_DIR}/${FIREBOLT_NAMESPACE}Config.cmake" - @ONLY) \ No newline at end of file + @ONLY) diff --git a/languages/cpp/src/shared/src/CMakeLists.txt b/languages/cpp/src/shared/src/CMakeLists.txt index 2530df90..190f5ade 100644 --- a/languages/cpp/src/shared/src/CMakeLists.txt +++ b/languages/cpp/src/shared/src/CMakeLists.txt @@ -22,16 +22,22 @@ set(TARGET ${PROJECT_NAME}) message("Setup ${TARGET} v${PROJECT_VERSION}") file(GLOB SOURCES *.cpp) -add_library(${TARGET} ${FIREBOLT_LIBRARY_TYPE} - ${SOURCES} +list(APPEND SOURCES Logger/Logger.cpp Gateway/Gateway.cpp Transport/Transport.cpp Accessor/Accessor.cpp - Event/Event.cpp Async/Async.cpp ) +if (ENABLE_BIDRECTIONAL) + list(APPEND SOURCES Event/bidi/Event.cpp) +else () + list(APPEND SOURCES Event/unidi/Event.cpp) +endif () + +add_library(${TARGET} ${FIREBOLT_LIBRARY_TYPE} ${SOURCES}) + if(ENABLE_UNIT_TESTS) target_compile_definitions(FireboltSDK PRIVATE UNIT_TEST) endif() @@ -83,4 +89,4 @@ install( InstallHeaders(TARGET ${TARGET} HEADERS . NAMESPACE ${FIREBOLT_NAMESPACE} DESTINATION ${FIREBOLT_NAMESPACE}SDK) InstallCMakeConfig(TARGETS ${TARGET}) -InstallPackageConfig(TARGETS ${TARGET} DESCRIPTION "Firebolt SDK Library") \ No newline at end of file +InstallPackageConfig(TARGETS ${TARGET} DESCRIPTION "Firebolt SDK Library") diff --git a/languages/cpp/src/shared/src/Event/Event.h b/languages/cpp/src/shared/src/Event/Event.h index 6e599716..30497d9d 100644 --- a/languages/cpp/src/shared/src/Event/Event.h +++ b/languages/cpp/src/shared/src/Event/Event.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Comcast Cable Communications Management, LLC + * Copyright 2024 Comcast Cable Communications Management, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,162 +15,16 @@ * * SPDX-License-Identifier: Apache-2.0 */ - #pragma once -#include "Module.h" - -namespace FireboltSDK { +#ifdef GATEWAY_BIDIRECTIONAL +#include "bidi/Event.h" +#else +#include "unidi/Event.h" +#endif +namespace FireboltSDK +{ static constexpr uint32_t DefaultWaitTime = 1000; +} - class Event : public IEventHandler { - public: - typedef std::function DispatchFunction; - private: - enum State : uint8_t { - IDLE, - EXECUTING, - REVOKED - }; - - struct CallbackData { - const DispatchFunction lambda; - const void* userdata; - State state; - }; - using CallbackMap = std::map; - using EventMap = std::map; - - class Response : public WPEFramework::Core::JSON::Container { - public: - Response& operator=(const Response&) = delete; - Response() - : WPEFramework::Core::JSON::Container() - , Listening(false) - { - Add(_T("listening"), &Listening); - } - Response(const Response& copy) - : WPEFramework::Core::JSON::Container() - , Listening(copy.Listening) - { - Add(_T("listening"), &Listening); - } - ~Response() override = default; - - public: - WPEFramework::Core::JSON::Boolean Listening; - }; - - private: - Event(); - public: - ~Event() override; - static Event& Instance(); - static void Dispose(); - void Configure(Transport* transport); - - public: - template - Firebolt::Error Subscribe(const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata) - { - JsonObject jsonParameters; - return Subscribe(eventName, jsonParameters, callback, usercb, userdata); - } - - template - 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); - - 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, prioritize); - - if (status != Firebolt::Error::None) { - Revoke(eventName, usercb); - } 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(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); - actualCallback(usercb, userdata, static_cast(inbound)); - return (Firebolt::Error::None); - }; - CallbackData callbackData = {implementation, userdata, State::IDLE}; - _adminLock.Lock(); - 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; - } - } else { - - 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)); - status = Firebolt::Error::None; - - } - - _adminLock.Unlock(); - return status; - } - Firebolt::Error Revoke(const string& eventName, void* usercb); - - private: - void Clear(); - 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 _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/Event/bidi/Event.cpp b/languages/cpp/src/shared/src/Event/bidi/Event.cpp new file mode 100644 index 00000000..da106236 --- /dev/null +++ b/languages/cpp/src/shared/src/Event/bidi/Event.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2023 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "Event.h" + +namespace FireboltSDK { + + Event* Event::_singleton = nullptr; + + /* static */ Event& Event::Instance() + { + static Event *instance = new Event(); + ASSERT(instance != nullptr); + return *instance; + } + + /* static */ void Event::Dispose() + { + ASSERT(_singleton != nullptr); + + if (_singleton != nullptr) { + delete _singleton; + } + } +} diff --git a/languages/cpp/src/shared/src/Event/bidi/Event.h b/languages/cpp/src/shared/src/Event/bidi/Event.h new file mode 100644 index 00000000..c7a55bff --- /dev/null +++ b/languages/cpp/src/shared/src/Event/bidi/Event.h @@ -0,0 +1,72 @@ +/* + * Copyright 2023 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "Module.h" +#include "Gateway/Gateway.h" + +namespace FireboltSDK { + + class Event { + private: + static Event* _singleton; + + private: + Event() + { + ASSERT(_singleton == nullptr); + _singleton = this; + } + + public: + virtual ~Event() + { + _singleton = nullptr; + } + + static Event& Instance(); + static void Dispose(); + void Configure(Transport* transport) {} + + public: + template + Firebolt::Error Subscribe(const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata) + { + JsonObject jsonParameters; + return Subscribe(eventName, jsonParameters, callback, usercb, userdata); + } + + template + Firebolt::Error Subscribe(const string& eventName, JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata, bool prioritize = false) + { + return Gateway::Instance().Subscribe(eventName, jsonParameters, callback, usercb, userdata, prioritize); + } + + Firebolt::Error Unsubscribe(const string& eventName, void* usercb) + { + return Gateway::Instance().Unsubscribe(eventName); + } + + template + Firebolt::Error Prioritize(const string& eventName,JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata) + { + Firebolt::Error status = Firebolt::Error::General; + return status; + } + }; +} diff --git a/languages/cpp/src/shared/src/Event/Event.cpp b/languages/cpp/src/shared/src/Event/unidi/Event.cpp similarity index 100% rename from languages/cpp/src/shared/src/Event/Event.cpp rename to languages/cpp/src/shared/src/Event/unidi/Event.cpp diff --git a/languages/cpp/src/shared/src/Event/unidi/Event.h b/languages/cpp/src/shared/src/Event/unidi/Event.h new file mode 100644 index 00000000..13e4c2df --- /dev/null +++ b/languages/cpp/src/shared/src/Event/unidi/Event.h @@ -0,0 +1,174 @@ +/* + * Copyright 2023 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "Module.h" + +namespace FireboltSDK +{ + class Event : public IEventHandler { + public: + typedef std::function DispatchFunction; + private: + enum State : uint8_t { + IDLE, + EXECUTING, + REVOKED + }; + + struct CallbackData { + const DispatchFunction lambda; + const void* userdata; + State state; + }; + using CallbackMap = std::map; + using EventMap = std::map; + + class Response : public WPEFramework::Core::JSON::Container { + public: + Response& operator=(const Response&) = delete; + Response() + : WPEFramework::Core::JSON::Container() + , Listening(false) + { + Add(_T("listening"), &Listening); + } + Response(const Response& copy) + : WPEFramework::Core::JSON::Container() + , Listening(copy.Listening) + { + Add(_T("listening"), &Listening); + } + ~Response() override = default; + + public: + WPEFramework::Core::JSON::Boolean Listening; + }; + + private: + Event(); + public: + ~Event() override; + static Event& Instance(); + static void Dispose(); + void Configure(Transport* transport); + + public: + template + Firebolt::Error Subscribe(const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata) + { + JsonObject jsonParameters; + return Subscribe(eventName, jsonParameters, callback, usercb, userdata); + } + + template + 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); + + 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, prioritize); + + if (status != Firebolt::Error::None) { + Revoke(eventName, usercb); + } 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(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); + actualCallback(usercb, userdata, static_cast(inbound)); + return (Firebolt::Error::None); + }; + CallbackData callbackData = {implementation, userdata, State::IDLE}; + _adminLock.Lock(); + 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; + } + } else { + + 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)); + status = Firebolt::Error::None; + + } + + _adminLock.Unlock(); + return status; + } + Firebolt::Error Revoke(const string& eventName, void* usercb); + + private: + void Clear(); + 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 _internalEventMap; + EventMap _externalEventMap; + WPEFramework::Core::CriticalSection _adminLock; + Transport* _transport; + + static Event* _singleton; + }; +} diff --git a/languages/cpp/src/shared/src/Gateway/Gateway.cpp b/languages/cpp/src/shared/src/Gateway/Gateway.cpp index 1b84c1b5..49994632 100644 --- a/languages/cpp/src/shared/src/Gateway/Gateway.cpp +++ b/languages/cpp/src/shared/src/Gateway/Gateway.cpp @@ -20,40 +20,40 @@ namespace FireboltSDK { -Gateway* Gateway::_instance = nullptr; +Gateway* Gateway::instance = nullptr; Gateway& Gateway::Instance() { - if (_instance == nullptr) { - _instance = new Gateway(new GatewayImpl()); - ASSERT(_instance != nullptr); + if (instance == nullptr) { + instance = new Gateway(std::make_unique()); + ASSERT(instance != nullptr); } - return *_instance; + return *instance; } void Gateway::Dispose() { - ASSERT(_instance != nullptr); - if (_instance != nullptr) { - delete _instance; - _instance = nullptr; + ASSERT(instance != nullptr); + if (instance != nullptr) { + delete instance; + instance = nullptr; } } -Gateway::Gateway(GatewayImpl *implementation) - : _implementation(implementation) +Gateway::Gateway(std::unique_ptr implementation) + : implementation(implementation.release()) { - _instance = this; + instance = this; } Gateway::~Gateway() { - delete _implementation; + implementation.reset(); } void Gateway::Configure(Transport* transport) { - _implementation->Configure(transport); + implementation->Configure(transport); } } diff --git a/languages/cpp/src/shared/src/Gateway/Gateway.h b/languages/cpp/src/shared/src/Gateway/Gateway.h index 32f99d61..0c50a910 100644 --- a/languages/cpp/src/shared/src/Gateway/Gateway.h +++ b/languages/cpp/src/shared/src/Gateway/Gateway.h @@ -25,32 +25,32 @@ #include "Transport/Transport.h" +#include "common.h" + #include #include #ifdef GATEWAY_BIDIRECTIONAL -#include "gateway_impl_bidi.h" +#include "bidi/gateway_impl.h" #else -#include "gateway_impl_unidi.h" +#include "unidi/gateway_impl.h" #endif namespace FireboltSDK { - using EventCallback = std::function; - class Gateway { - static Gateway *_instance; + static Gateway *instance; - GatewayImpl *_implementation; + std::unique_ptr implementation; private: - Gateway(GatewayImpl *implementation); + Gateway(std::unique_ptr implementation); public: Gateway(const Gateway&) = delete; Gateway& operator=(const Gateway&) = delete; - ~Gateway(); + virtual ~Gateway(); static Gateway& Instance(); static void Dispose(); @@ -60,20 +60,36 @@ namespace FireboltSDK template Firebolt::Error Request(const std::string &method, const JsonObject ¶meters, RESPONSETYPE &response) { - return _implementation->Request(method, parameters, response); + return implementation->Request(method, parameters, response); } +#ifdef GATEWAY_BIDIRECTIONAL + template + Firebolt::Error Subscribe(const string& event, JsonObject& parameters, const CALLBACK& callback, void* usercb, const void* userdata, bool prioritize = false) + { + return implementation->Subscribe(event, parameters, callback, usercb, userdata, prioritize); + } + + Firebolt::Error Unsubscribe(const std::string& event) + { + return implementation->Unsubscribe(event); + } +#else template Firebolt::Error Subscribe(const string& event, const string& parameters, RESPONSETYPE& response) { - return _implementation->Subscribe(event, parameters, response); + return implementation->Subscribe(event, parameters, response); } Firebolt::Error Unsubscribe(const string& event, const string& parameters) { - return _implementation->Unsubscribe(event, parameters); + return implementation->Unsubscribe(event, parameters); + } +#endif + Firebolt::Error RegisterProviderInterface(const std::string &capability, const std::string &interface, const std::string &method, const JsonObject ¶meters, const ProviderCallback& callback) + { + return implementation->RegisterProviderInterface(capability, interface, method, parameters, callback); } - }; } diff --git a/languages/cpp/src/shared/src/Gateway/bidi/client.h b/languages/cpp/src/shared/src/Gateway/bidi/client.h new file mode 100644 index 00000000..70c81984 --- /dev/null +++ b/languages/cpp/src/shared/src/Gateway/bidi/client.h @@ -0,0 +1,161 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME OpenRPCNativeSDK +#endif +#include +#include "error.h" + +#include "../common.h" + +#include "Transport/Transport.h" + +#include +#include +#include +#include +#include +#include + +namespace FireboltSDK +{ + class Client + { + struct Caller + { + Caller(MessageID id_) + : id(id_) + , timestamp(std::chrono::steady_clock::now()) + {} + + MessageID id; + Timestamp timestamp; + std::string response; + Firebolt::Error error = Firebolt::Error::None; + bool ready = false; + std::mutex mtx; + std::condition_variable waiter; + }; + + std::map > queue; + mutable std::mutex queue_mtx; + Transport* transport; + Config config; + + std::atomic running { false }; + std::thread watchdogThread; + + void watchdog() + { + auto watchdogTimer = std::chrono::milliseconds(config.watchdogCycle_ms); + std::vector> outdated; + + while (running) { + Timestamp now = std::chrono::steady_clock::now(); + { + std::lock_guard lck(queue_mtx); + for (auto it = queue.begin(); it != queue.end();) { + if (std::chrono::duration_cast(now - it->second->timestamp).count() > config.watchdogThreshold_ms) { + outdated.push_back(it->second); + it = queue.erase(it); + } else { + ++it; + } + } + } + for (auto &c : outdated) { + std::unique_lock lk(c->mtx); + c->ready = true; + c->error = Firebolt::Error::Timedout; + c->waiter.notify_one(); + } + outdated.clear(); + std::this_thread::sleep_for(watchdogTimer); + } + } + + public: + void Configure(Transport* transport, const Config &config) + { + this->transport = transport; + this->config = config; + running = false; + watchdogThread = std::thread(std::bind(&Client::watchdog, this)); + } + + virtual ~Client() + { + running = false; + if (watchdogThread.joinable()) { + watchdogThread.join(); + } + } + + template + Firebolt::Error Request(const std::string &method, const JsonObject ¶meters, RESPONSETYPE &response) + { + if (transport == nullptr) { + return Firebolt::Error::NotConnected; + } + + MessageID id = transport->GetNextMessageID(); + std::shared_ptr c = std::make_shared(id); + { + std::lock_guard lck(queue_mtx); + queue[id] = c; + } + + Firebolt::Error result = transport->Send(method, parameters, id); + if (result == Firebolt::Error::None) { + std::unique_lock lk(c->mtx); + c->waiter.wait(lk, [&]{ return c->ready; }); + response.FromString(c->response); + } + + return result; + } + + bool IdRequested(MessageID id) + { + std::lock_guard lck(queue_mtx); + return queue.find(id) != queue.end(); + } + + void Response(const WPEFramework::Core::JSONRPC::Message& message) + { + MessageID id = message.Id.Value(); + try { + std::lock_guard lck(queue_mtx); + auto c = queue.at(id); + std::unique_lock lk(c->mtx); + + if (!message.Error.IsSet()) { + c->response = message.Result.Value(); + } else { + c->error = static_cast(message.Error.Code.Value()); + } + c->ready = true; + c->waiter.notify_one(); + } catch (const std::out_of_range &e) { + } + } + }; +} + diff --git a/languages/cpp/src/shared/src/Gateway/bidi/gateway_impl.h b/languages/cpp/src/shared/src/Gateway/bidi/gateway_impl.h new file mode 100644 index 00000000..7906747d --- /dev/null +++ b/languages/cpp/src/shared/src/Gateway/bidi/gateway_impl.h @@ -0,0 +1,148 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME OpenRPCNativeSDK +#endif +#include +#include "error.h" + +#include "Transport/Transport.h" + +#include "../common.h" +#include "client.h" +#include "server.h" + +#include + +namespace FireboltSDK +{ + class ListeningResponse : public WPEFramework::Core::JSON::Container { + public: + ListeningResponse& operator=(const ListeningResponse&) = delete; + ListeningResponse() + : WPEFramework::Core::JSON::Container() + , Listening(false) + { + Add(_T("listening"), &Listening); + } + ListeningResponse(const ListeningResponse& copy) + : WPEFramework::Core::JSON::Container() + , Listening(copy.Listening) + { + Add(_T("listening"), &Listening); + } + ~ListeningResponse() override = default; + + public: + WPEFramework::Core::JSON::Boolean Listening; + }; + class GatewayImpl : public ITransportReceiver + { + Config config; + Client client; + Server server; + Transport* transport; + + public: + void Configure(Transport* transport) + { + client.Configure(transport, config); + server.Configure(config); + this->transport = transport; + transport->SetTransportReceiver(this); + } + + virtual void Receive(const WPEFramework::Core::JSONRPC::Message& message) override + { + if (message.Id.IsSet() == true) { + if (client.IdRequested(message.Id.Value())) { + client.Response(message); + } else { + server.Request(message); + } + } else { + server.Notify(message); + } + } + + template + Firebolt::Error Request(const std::string &method, const JsonObject ¶meters, RESPONSETYPE &response) + { + if (transport == nullptr) { + return Firebolt::Error::NotConnected; + } + return client.Request(method, parameters, response); + } + + // TODO: Do we need 'parameters' as an arg? + template + Firebolt::Error Subscribe(const string& event, JsonObject& parameters, const CALLBACK& callback, void* usercb, const void* userdata, bool prioritize = false) + { + if (transport == nullptr) { + return Firebolt::Error::NotConnected; + } + + Firebolt::Error status = server.Subscribe(event, parameters, callback, usercb, userdata); + if (status != Firebolt::Error::None) { + return status; + } + + ListeningResponse response; + WPEFramework::Core::JSON::Variant Listen = true; + parameters.Set(_T("listen"), Listen); + std::string params; + parameters.ToString(params); + status = client.Request(event, params, response); + if (status == Firebolt::Error::None && (!response.Listening.IsSet() || !response.Listening.Value())) { + status == Firebolt::Error::General; + } + if (status != Firebolt::Error::None) { + server.Unsubscribe(event); + } + return status; + } + + Firebolt::Error Unsubscribe(const string& event) + { + Firebolt::Error status = server.Unsubscribe(event); + if (status != Firebolt::Error::None) { + return status; + } + ListeningResponse response; + WPEFramework::Core::JSON::Variant Listen = false; + JsonObject parameters; + parameters.Set(_T("listen"), Listen); + std::string params; + parameters.ToString(params); + status = client.Request(event, params, response); + if (status == Firebolt::Error::None && (!response.Listening.IsSet() || !response.Listening.Value())) { + status == Firebolt::Error::General; + } + return status; + } + + Firebolt::Error RegisterProviderInterface(const std::string &capability, const std::string &interface, const std::string &method, const JsonObject ¶meters, const ProviderCallback& callback) + { + return server.RegisterProviderInterface(capability, interface, method, parameters, callback); + } + + }; +} + diff --git a/languages/cpp/src/shared/src/Gateway/bidi/server.h b/languages/cpp/src/shared/src/Gateway/bidi/server.h new file mode 100644 index 00000000..00fbee77 --- /dev/null +++ b/languages/cpp/src/shared/src/Gateway/bidi/server.h @@ -0,0 +1,187 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME OpenRPCNativeSDK +#endif +#include +#include "error.h" + +#include "../common.h" + +#include +#include +#include +#include + +namespace FireboltSDK +{ + class Server + { + using DispatchFunction = std::function; + + struct CallbackData { + const DispatchFunction lambda; + void* usercb; + const void* userdata; + }; + + using EventMap = std::map; + + EventMap eventMap; + mutable std::mutex eventMap_mtx; + + struct Method { + std::string name; + JsonObject parameters; + ProviderCallback callback; + }; + + struct Interface { + std::string capability; + std::string name; + std::list methods; + }; + + std::map providers; + mutable std::mutex providers_mtx; + + Config config; + + template + Firebolt::Error Assign(const string& event, JsonObject& parameters, 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); + actualCallback(usercb, userdata, static_cast(inbound)); + return (Firebolt::Error::None); + }; + CallbackData callbackData = {implementation, usercb, userdata}; + + std::lock_guard lck(eventMap_mtx); + + EventMap::iterator eventIndex = eventMap.find(event); + if (eventIndex == eventMap.end()) { + eventMap.emplace(std::piecewise_construct, std::forward_as_tuple(event), std::forward_as_tuple(callbackData)); + status = Firebolt::Error::None; + } + + return status; + } + + public: + virtual ~Server() + { + std::lock_guard lck(eventMap_mtx); + eventMap.clear(); + } + + void Configure(const Config &config) + { + this->config = config; + } + + template + Firebolt::Error Subscribe(const string& event, JsonObject& parameters, const CALLBACK& callback, void* usercb, const void* userdata) + { + Firebolt::Error status = Firebolt::Error::General; + + status = Assign(event, parameters, callback, usercb, userdata); + + return status; + } + + Firebolt::Error Unsubscribe(const string& event) + { + std::lock_guard lck(eventMap_mtx); + return eventMap.erase(event) > 0 ? Firebolt::Error::None : Firebolt::Error::General; + } + + // TODO: check format of 'event' message from the platform in bi-directional + void Notify(const WPEFramework::Core::JSONRPC::Message& message) + { + string response = message.Result.Value(); + size_t dotPos = response.find('.'); + if (dotPos == std::string::npos) { + return; + } + std::string event = response.substr(0, dotPos); + std::string method = response.substr(dotPos + 1); + + std::lock_guard lck(eventMap_mtx); + EventMap::iterator eventIt = eventMap.find(event); + if (eventIt != eventMap.end()) { + CallbackData& callback = eventIt->second; + callback.lambda(callback.usercb, callback.userdata, response); + } + } + + void Request(const WPEFramework::Core::JSONRPC::Message& message) + { + } + + void Request(const std::string &methodFullName, const JsonObject ¶meters) + { + size_t dotPos = methodFullName.find('.'); + if (dotPos == std::string::npos) { + return; + } + std::string interface = methodFullName.substr(0, dotPos);; + std::string methodName = methodFullName.substr(dotPos + 1); + std::lock_guard lck(providers_mtx); + auto provider = providers.find(interface); + if (provider == providers.end()) { + return; + } + auto& methods = provider->second.methods; + auto it = methods.begin(); + while (it != methods.end()) { + if ((it = std::find_if(it, methods.end(), [&methodName](const Method &m) { return m.name == methodName; })) != methods.end()) { + auto& m = *it; + m.callback(parameters); + } + } + } + + Firebolt::Error RegisterProviderInterface(const std::string &capability, const std::string &interface, const std::string &method, const JsonObject ¶meters, const ProviderCallback &callback) + { + Interface i; + std::lock_guard lck(providers_mtx); + if (providers.find(interface) == providers.end()) { + i = { + .capability = capability, + .name = interface, + }; + } else { + i = providers[interface]; + } + i.methods.push_back({ + .name = method, + .parameters = parameters, + .callback = callback + }); + return Firebolt::Error::None; + } + }; +} + diff --git a/languages/cpp/src/shared/src/Gateway/common.h b/languages/cpp/src/shared/src/Gateway/common.h new file mode 100644 index 00000000..67e13023 --- /dev/null +++ b/languages/cpp/src/shared/src/Gateway/common.h @@ -0,0 +1,35 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include + +namespace FireboltSDK +{ + using Timestamp = std::chrono::time_point; + using MessageID = uint32_t; + using ProviderCallback = std::function; + + struct Config + { + uint64_t watchdogThreshold_ms = 3000; + uint64_t watchdogCycle_ms = 500; + }; +} + diff --git a/languages/cpp/src/shared/src/Gateway/gateway_impl_bidi.h b/languages/cpp/src/shared/src/Gateway/gateway_impl_bidi.h deleted file mode 100644 index f43adad9..00000000 --- a/languages/cpp/src/shared/src/Gateway/gateway_impl_bidi.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2024 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include "error.h" -#include "Accessor/Accessor.h" - -#include -#include - -namespace FireboltSDK -{ - - using EventCallback = std::function; - - class Client - { - Firebolt::Error Request(const std::string &method, const JsonObject ¶meters) - { - return Firebolt::Error::None; - } - }; - - class Server - { - Firebolt::Error Subscribe(const std::string &eventName, const EventCallback &callback) - { - return Firebolt::Error::None; - } - - Firebolt::Error Request(const std::string &methodName, const JsonObject ¶meters) - { - return Firebolt::Error::None; - } - - Firebolt::Error Notify() - { - return Firebolt::Error::None; - } - }; - - class Provider - { - // TBD - }; - - class GatewayImpl : public Gateway - { - Client _client; - Server _server; - - void receive(const JsonObject &response) - { - - } - - public: - Firebolt::Error Request(const std::string &method, const JsonObject ¶meters, JsonObject &response) - { - return _client.Request(method, parameters); - } - - virtual Firebolt::Error Subscribe(const std::string &eventName, const EventCallback &callback) - { - return _server.Subscribe(eventName, callback); - } - - virtual Firebolt::Error Unsubsribe(const std::string &eventName) - { - return Firebolt::Error::None; - } - - virtual Firebolt::Error Provide(const std::string &interfaceName, const Provider &provider) - { - return Firebolt::Error::None; - } - } -} - diff --git a/languages/cpp/src/shared/src/Gateway/gateway_impl_unidi.h b/languages/cpp/src/shared/src/Gateway/unidi/gateway_impl.h similarity index 72% rename from languages/cpp/src/shared/src/Gateway/gateway_impl_unidi.h rename to languages/cpp/src/shared/src/Gateway/unidi/gateway_impl.h index 596b651e..94a45321 100644 --- a/languages/cpp/src/shared/src/Gateway/gateway_impl_unidi.h +++ b/languages/cpp/src/shared/src/Gateway/unidi/gateway_impl.h @@ -23,6 +23,8 @@ #include #include "error.h" +#include "../common.h" + #include "Transport/Transport.h" #include @@ -36,7 +38,7 @@ namespace FireboltSDK class GatewayImpl { - Transport* _transport; + Transport* transport; public: GatewayImpl() @@ -47,39 +49,39 @@ namespace FireboltSDK void Configure(Transport* transport) { - _transport = transport; + transport = transport; } template Firebolt::Error Request(const std::string &method, const JsonObject ¶meters, RESPONSETYPE &response) { - if (_transport == nullptr) { + if (transport == nullptr) { return Firebolt::Error::NotConnected; } - return _transport->Invoke(method, parameters, response); + return transport->Invoke(method, parameters, response); } template Firebolt::Error Subscribe(const string& event, const string& parameters, RESPONSETYPE& response) { - if (_transport == nullptr) { + if (transport == nullptr) { return Firebolt::Error::NotConnected; } - return _transport->Subscribe(event, parameters, response); + return transport->Subscribe(event, parameters, response); } Firebolt::Error Unsubscribe(const string& event, const string& parameters) { - if (_transport == nullptr) { + if (transport == nullptr) { return Firebolt::Error::NotConnected; } - return _transport->Unsubscribe(event, parameters); + return transport->Unsubscribe(event, parameters); } - // virtual Firebolt::Error Provide(const std::string &interfaceName, const Provider &provider) - // { - // return Firebolt::Error::None; - // } + Firebolt::Error RegisterProviderInterface(const std::string &capability, const std::string &interface, const std::string &method, const JsonObject ¶meters, const ProviderCallback& callback) + { + return Firebolt::Error::General; + } }; } diff --git a/languages/cpp/src/shared/src/Transport/Transport_bidi.h b/languages/cpp/src/shared/src/Transport/Transport_bidi.h index 3d56e7be..7a4b6cfb 100644 --- a/languages/cpp/src/shared/src/Transport/Transport_bidi.h +++ b/languages/cpp/src/shared/src/Transport/Transport_bidi.h @@ -27,6 +27,11 @@ namespace FireboltSDK { using namespace WPEFramework::Core::TypeTraits; + class ITransportReceiver { + public: + virtual void Receive(const WPEFramework::Core::JSONRPC::Message& message) = 0; + }; + class IEventHandler { public: @@ -123,7 +128,7 @@ namespace FireboltSDK Transport(const Transport &) = delete; Transport &operator=(Transport &) = delete; Transport(const WPEFramework::Core::URL &url, const uint32_t waitTime, const Listener listener) - : _adminLock(), _connectId(WPEFramework::Core::NodeId(url.Host().Value().c_str(), url.Port().Value())), _channel(Channel::Instance(_connectId, ((url.Path().Value().rfind(PathPrefix, 0) == 0) ? url.Path().Value() : string(PathPrefix + url.Path().Value())), url.Query().Value(), true)), _eventHandler(nullptr), _pendingQueue(), _scheduledTime(0), _waitTime(waitTime), _listener(listener), _connected(false), _status(Firebolt::Error::NotConnected) + : _adminLock(), _connectId(WPEFramework::Core::NodeId(url.Host().Value().c_str(), url.Port().Value())), _channel(Channel::Instance(_connectId, ((url.Path().Value().rfind(PathPrefix, 0) == 0) ? url.Path().Value() : string(PathPrefix + url.Path().Value())), url.Query().Value(), true)), _pendingQueue(), _scheduledTime(0), _waitTime(waitTime), _listener(listener), _connected(false), _status(Firebolt::Error::NotConnected) { _channel->Register(*this); WPEFramework::Core::ProxyType job = WPEFramework::Core::ProxyType(WPEFramework::Core::ProxyType::Create(this)); @@ -142,18 +147,10 @@ namespace FireboltSDK public: -// Always return true for unit testing -#ifdef UNIT_TEST - inline bool IsOpen() - { - return true; - } -#else inline bool IsOpen() { return _channel->IsOpen(); - } -#endif + } void Revoke(const string &eventName) { @@ -168,26 +165,13 @@ namespace FireboltSDK void SetEventHandler(IEventHandler *eventHandler) { - _eventHandler = eventHandler; } -// Invoke method is overriden for unit testing to call MockResponse method from JSON engine -#ifdef UNIT_TEST - template - Firebolt::Error Invoke(const string &method, const PARAMETERS ¶meters, RESPONSE &response) + void SetTransportReceiver(ITransportReceiver *transportReceiver) { - Entry slot; - uint32_t id = _channel->Sequence(); - Firebolt::Error result = Send(method, parameters, id); - - WPEFramework::Core::JSONRPC::Message message; - message.Designator = method; - std::unique_ptr jsonEngine = std::make_unique(); - result = jsonEngine->MockResponse(message, response); - FromMessage((INTERFACE *)&response, message); - return (result); + _transportReceiver = transportReceiver; } -#else + template Firebolt::Error Invoke(const string& method, const PARAMETERS& parameters, RESPONSE& response) { @@ -200,7 +184,6 @@ namespace FireboltSDK return (result); } -#endif template Firebolt::Error InvokeAsync(const string &method, const PARAMETERS ¶meters, uint32_t &id) @@ -254,6 +237,11 @@ namespace FireboltSDK slot.Abort(id); } + uint32_t GetNextMessageID() + { + return _channel->Sequence(); + } + template Firebolt::Error Subscribe(const string& eventName, const string& parameters, RESPONSE& response, bool updateInternal = false) { @@ -314,6 +302,47 @@ namespace FireboltSDK return (((waiting == 0) || (IsOpen() == true)) ? Firebolt::Error::None : Firebolt::Error::Timedout); } + template + Firebolt::Error Send(const string &method, const PARAMETERS ¶meters, const uint32_t &id) + { + int32_t result = WPEFramework::Core::ERROR_UNAVAILABLE; + + if ((_channel.IsValid() == true) && (_channel->IsSuspended() == true)) + { + result = WPEFramework::Core::ERROR_ASYNC_FAILED; + } + else if (_channel.IsValid() == true) + { + + result = WPEFramework::Core::ERROR_ASYNC_FAILED; + + WPEFramework::Core::ProxyType message(Channel::Message()); + message->Id = id; + message->Designator = method; + ToMessage(parameters, message); + + _adminLock.Lock(); + + typename std::pair newElement = + _pendingQueue.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple()); + ASSERT(newElement.second == true); + + if (newElement.second == true) + { + + _adminLock.Unlock(); + + _channel->Submit(WPEFramework::Core::ProxyType(message)); + + message.Release(); + result = WPEFramework::Core::ERROR_NONE; + } + } + return FireboltErrorValue(result); + } + private: friend Channel; inline bool IsEvent(const uint32_t id, string& eventName) @@ -416,160 +445,14 @@ namespace FireboltSDK ASSERT(inbound.IsValid() == true); - if ((inbound->Id.IsSet() == true) && (inbound->Result.IsSet() || inbound->Error.IsSet())) - { - // Looks like this is a response.. - ASSERT(inbound->Parameters.IsSet() == false); - ASSERT(inbound->Designator.IsSet() == false); - - _adminLock.Lock(); - - // See if we issued this.. - typename PendingMap::iterator index = _pendingQueue.find(inbound->Id.Value()); - - if (index != _pendingQueue.end()) - { - - if (index->second.Signal(inbound) == true) - { - _pendingQueue.erase(index); - } - - result = WPEFramework::Core::ERROR_NONE; - _adminLock.Unlock(); - } - else - { - _adminLock.Unlock(); - string eventName; - if (IsEvent(inbound->Id.Value(), eventName)) - { - _eventHandler->Dispatch(eventName, inbound); - } - } + if (_transportReceiver != nullptr) { + _transportReceiver->Receive(*inbound); } return (result); } - template - Firebolt::Error Send(const string &method, const PARAMETERS ¶meters, const uint32_t &id) - { - int32_t result = WPEFramework::Core::ERROR_UNAVAILABLE; - - if ((_channel.IsValid() == true) && (_channel->IsSuspended() == true)) - { - result = WPEFramework::Core::ERROR_ASYNC_FAILED; - } - else if (_channel.IsValid() == true) - { - - result = WPEFramework::Core::ERROR_ASYNC_FAILED; - - WPEFramework::Core::ProxyType message(Channel::Message()); - message->Id = id; - message->Designator = method; - ToMessage(parameters, message); - - _adminLock.Lock(); - - typename std::pair newElement = - _pendingQueue.emplace(std::piecewise_construct, - std::forward_as_tuple(id), - std::forward_as_tuple()); - ASSERT(newElement.second == true); - - if (newElement.second == true) - { - - _adminLock.Unlock(); - - _channel->Submit(WPEFramework::Core::ProxyType(message)); - - message.Release(); - result = WPEFramework::Core::ERROR_NONE; - } - } - return FireboltErrorValue(result); - } -#ifdef UNIT_TEST -template - Firebolt::Error WaitForEventResponse(const uint32_t &id, const string &eventName, RESPONSE &response, const uint32_t waitTime, EventMap& _eventMap) - { - std::cout << "Inside Mock Transport WaitForEventResponse function" << std::endl; - std::cout << "Mock Transport WaitForEventResponse eventName: " << eventName << std::endl; - /* Since there is no return value for event subscription, error would be the only validation for now. - Returning a mock event response from open rpc would mean that the logic in WaitForEventResponse to check a queue is not used. - At which point, the function would no longer be validating the SDK functionality. - If the queue find functionality is to be tested, the _pendingQueue could be mocked in upcoming iterations. - */ - return Firebolt::Error::None; - } -#else static constexpr uint32_t WAITSLOT_TIME = 100; - template - Firebolt::Error WaitForEventResponse(const uint32_t &id, const string &eventName, RESPONSE &response, const uint32_t waitTime, EventMap& _eventMap) - { - std::cout << "Inside Transport WaitForEventResponse function" << std::endl; - Firebolt::Error result = Firebolt::Error::Timedout; - _adminLock.Lock(); - typename PendingMap::iterator index = _pendingQueue.find(id); - Entry &slot(index->second); - _adminLock.Unlock(); - - uint8_t waiting = waitTime; - do - { - uint32_t waitSlot = (waiting > WAITSLOT_TIME ? WAITSLOT_TIME : waiting); - if (slot.WaitForResponse(waitSlot) == true) - { - WPEFramework::Core::ProxyType jsonResponse = slot.Response(); - - // See if we have a jsonResponse, maybe it was just the connection - // that closed? - if (jsonResponse.IsValid() == true) - { - if (jsonResponse->Error.IsSet() == true) - { - result = FireboltErrorValue(jsonResponse->Error.Code.Value()); - } - else - { - if ((jsonResponse->Result.IsSet() == true) && (jsonResponse->Result.Value().empty() == false)) - { - bool enabled; - result = _eventHandler->ValidateResponse(jsonResponse, enabled); - if (result == Firebolt::Error::None) - { - FromMessage((INTERFACE *)&response, *jsonResponse); - if (enabled) - { - _adminLock.Lock(); - typename EventMap::iterator index = _eventMap.find(eventName); - if (index != _eventMap.end()) - { - index->second = id; - } - _adminLock.Unlock(); - } - } - } - } - } - } - else - { - result = Firebolt::Error::Timedout; - } - waiting -= (waiting == WPEFramework::Core::infinite ? 0 : waitSlot); - } while ((result != Firebolt::Error::None) && (waiting > 0)); - _adminLock.Lock(); - _pendingQueue.erase(id); - _adminLock.Unlock(); - - return result; - } -#endif public: void FromMessage(WPEFramework::Core::JSON::IElement *response, const WPEFramework::Core::JSONRPC::Message &message) const { @@ -648,7 +531,7 @@ template WPEFramework::Core::CriticalSection _adminLock; WPEFramework::Core::NodeId _connectId; WPEFramework::Core::ProxyType _channel; - IEventHandler *_eventHandler; + ITransportReceiver *_transportReceiver; PendingMap _pendingQueue; EventMap _internalEventMap; EventMap _externalEventMap; @@ -659,4 +542,4 @@ template bool _connected; Firebolt::Error _status; }; -} \ No newline at end of file +} diff --git a/languages/cpp/templates/sdk/scripts/build.sh b/languages/cpp/templates/sdk/scripts/build.sh index 3a3bf7f0..1c8732a7 100755 --- a/languages/cpp/templates/sdk/scripts/build.sh +++ b/languages/cpp/templates/sdk/scripts/build.sh @@ -8,6 +8,7 @@ usage() echo " -c clear build" echo " -l enable static build" echo " -t enable test" + echo " -b enable bidirectional gateway" echo " -h : help" echo echo "usage: " @@ -19,6 +20,7 @@ EnableTest="OFF" SysrootPath=${SYSROOT_PATH} ClearBuild="N" EnableStaticLib="OFF" +EnableBidirectional="OFF" while getopts p:s:clth flag do case "${flag}" in @@ -27,6 +29,7 @@ do c) ClearBuild="Y";; l) EnableStaticLib="ON";; t) EnableTest="ON";; + b) EnableBidirectional="ON";; h) usage && exit 1;; esac done @@ -37,7 +40,7 @@ then fi rm -rf ${SdkPath}/build/src/libFireboltSDK.so -cmake -B${SdkPath}/build -S${SdkPath} -DSYSROOT_PATH=${SysrootPath} -DENABLE_TESTS=${EnableTest} -DHIDE_NON_EXTERNAL_SYMBOLS=OFF -DFIREBOLT_ENABLE_STATIC_LIB=${EnableStaticLib} || exit 1 +cmake -B${SdkPath}/build -S${SdkPath} -DSYSROOT_PATH=${SysrootPath} -DENABLE_TESTS=${EnableTest} -DHIDE_NON_EXTERNAL_SYMBOLS=OFF -DFIREBOLT_ENABLE_STATIC_LIB=${EnableStaticLib} -DENABLE_BIDRECTIONAL=${EnableBidirectional} || exit 1 cmake --build ${SdkPath}/build || exit 1 if [ -f "${SdkPath}/build/src/libFireboltSDK.so" ]; then