Skip to content

Commit

Permalink
feat: Implementation of bi-directional communication with platform
Browse files Browse the repository at this point in the history
Bidirectional is disabled by default. Can be in cmake: 'ENABLE_BIDRECTIONAL'.

UTs were executed with undefined UNIT_TEST.

SOME TESTS FAILED:
Test SubscribeDiscoveryOnNavigateToLaunchNotification failed:
  SubscribeDiscoveryOnNavigateToLaunchNotification failed. Error: 1
  • Loading branch information
tomasz-blasz committed Dec 20, 2024
1 parent 36347e2 commit 432e68a
Show file tree
Hide file tree
Showing 17 changed files with 961 additions and 470 deletions.
7 changes: 6 additions & 1 deletion languages/cpp/src/shared/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()
Expand Down Expand Up @@ -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)
@ONLY)
14 changes: 10 additions & 4 deletions languages/cpp/src/shared/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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")
InstallPackageConfig(TARGETS ${TARGET} DESCRIPTION "Firebolt SDK Library")
164 changes: 9 additions & 155 deletions languages/cpp/src/shared/src/Event/Event.h
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<Firebolt::Error(void*, const void*, const string& parameters)> DispatchFunction;
private:
enum State : uint8_t {
IDLE,
EXECUTING,
REVOKED
};

struct CallbackData {
const DispatchFunction lambda;
const void* userdata;
State state;
};
using CallbackMap = std::map<void*, CallbackData>;
using EventMap = std::map<string, CallbackMap>;

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<WPEFramework::Core::JSON::IElement>* transport);

public:
template <typename RESULT, typename CALLBACK>
Firebolt::Error Subscribe(const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata)
{
JsonObject jsonParameters;
return Subscribe<RESULT, CALLBACK>(eventName, jsonParameters, callback, usercb, userdata);
}

template <typename RESULT, typename CALLBACK>
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<RESULT, CALLBACK>(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<Response>(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 <typename RESULT, typename CALLBACK>
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<RESULT, CALLBACK>(eventName, jsonParameters, callback, usercb, userdata, true);
return status;
}


Firebolt::Error Unsubscribe(const string& eventName, void* usercb);

private:
template <typename PARAMETERS, typename CALLBACK>
Firebolt::Error Assign(EventMap& eventMap, const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata)
{

Firebolt::Error status = Firebolt::Error::General;
std::function<void(void* usercb, const void* userdata, void* parameters)> actualCallback = callback;
DispatchFunction implementation = [actualCallback](void* usercb, const void* userdata, const string& parameters) -> Firebolt::Error {
WPEFramework::Core::ProxyType<PARAMETERS>* inbound = new WPEFramework::Core::ProxyType<PARAMETERS>();
*inbound = WPEFramework::Core::ProxyType<PARAMETERS>::Create();
(*inbound)->FromString(parameters);
actualCallback(usercb, userdata, static_cast<void*>(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<WPEFramework::Core::JSONRPC::Message>& jsonResponse, bool& enabled) override;
Firebolt::Error Dispatch(const string& eventName, const WPEFramework::Core::ProxyType<WPEFramework::Core::JSONRPC::Message>& jsonResponse) override;

private:
EventMap _internalEventMap;
EventMap _externalEventMap;
WPEFramework::Core::CriticalSection _adminLock;
Transport<WPEFramework::Core::JSON::IElement>* _transport;

static Event* _singleton;
};
}
39 changes: 39 additions & 0 deletions languages/cpp/src/shared/src/Event/bidi/Event.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
72 changes: 72 additions & 0 deletions languages/cpp/src/shared/src/Event/bidi/Event.h
Original file line number Diff line number Diff line change
@@ -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<WPEFramework::Core::JSON::IElement>* transport) {}

public:
template <typename RESULT, typename CALLBACK>
Firebolt::Error Subscribe(const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata)
{
JsonObject jsonParameters;
return Subscribe<RESULT, CALLBACK>(eventName, jsonParameters, callback, usercb, userdata);
}

template <typename RESULT, typename CALLBACK>
Firebolt::Error Subscribe(const string& eventName, JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata, bool prioritize = false)
{
return Gateway::Instance().Subscribe<RESULT>(eventName, jsonParameters, callback, usercb, userdata, prioritize);
}

Firebolt::Error Unsubscribe(const string& eventName, void* usercb)
{
return Gateway::Instance().Unsubscribe(eventName);
}

template <typename RESULT, typename CALLBACK>
Firebolt::Error Prioritize(const string& eventName,JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata)
{
Firebolt::Error status = Firebolt::Error::General;
return status;
}
};
}
Loading

0 comments on commit 432e68a

Please sign in to comment.