Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CPPSDK : Add Async communication support and CPP code generation for x-uses + x-allow-focus=true #170

Merged
merged 2 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions languages/cpp/src/shared/src/Accessor/Accessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "Module.h"
#include "WorkerPool.h"
#include "Transport/Transport.h"
#include "Async/Async.h"
#include "Event/Event.h"
#include "Logger/Logger.h"

Expand Down Expand Up @@ -108,6 +109,7 @@ namespace FireboltSDK {
{
Firebolt::Error status = CreateTransport(_config.WsUrl.Value().c_str(), listener, _config.WaitTime.Value());
if (status == Firebolt::Error::None) {
Async::Instance().Configure(_transport);
status = CreateEventHandler();
}
return status;
Expand All @@ -118,6 +120,7 @@ namespace FireboltSDK {
Firebolt::Error status = Firebolt::Error::None;
status = DestroyTransport();
if (status == Firebolt::Error::None) {
Async::Dispose();
status = DestroyEventHandler();
}
return status;
Expand Down
78 changes: 78 additions & 0 deletions languages/cpp/src/shared/src/Async/Async.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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 "Transport/Transport.h"
#include "Async.h"

namespace FireboltSDK {
Async* Async::_singleton = nullptr;
Async::Async()
: _methodMap()
, _adminLock()
, _transport(nullptr)
{
ASSERT(_singleton == nullptr);
_singleton = this;
}

Async::~Async() /* override */
{
Clear();
_transport = nullptr;
_singleton = nullptr;
}

/* static */ Async& Async::Instance()
{
static Async *instance = new Async();
ASSERT(instance != nullptr);
return *instance;
}

/* static */ void Async::Dispose()
{
ASSERT(_singleton != nullptr);

if (_singleton != nullptr) {
delete _singleton;
}
}

void Async::Configure(Transport<WPEFramework::Core::JSON::IElement>* transport)
{
_transport = transport;
}

void Async::Clear()
{
_adminLock.Lock();
MethodMap::iterator index = _methodMap.begin();
while (index != _methodMap.end()) {
CallbackMap::iterator callbackIndex = index->second.begin();
while (callbackIndex != index->second.end()) {
if (IsValidJob(callbackIndex->second)) {
WPEFramework::Core::IWorkerPool::Instance().Revoke(callbackIndex->second.job);
}
callbackIndex = index->second.erase(callbackIndex);
}
index = _methodMap.erase(index);
}
_adminLock.Unlock();
}
}

203 changes: 203 additions & 0 deletions languages/cpp/src/shared/src/Async/Async.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* 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 Async {
private:
Async();
public:
virtual ~Async();
Async(const Async&) = delete;
Async& operator= (const Async&) = delete;

public:
typedef std::function<Firebolt::Error(Async& parent, void*)> DispatchFunction;

class Job : public WPEFramework::Core::IDispatch {
protected:
Job(Async& parent, const string& method, const DispatchFunction lambda, void* usercb)
: _parent(parent)
, _method(method)
, _lambda(lambda)
, _usercb(usercb)
{
}

public:
Job() = delete;
Job(const Job&) = delete;
Job& operator=(const Job&) = delete;

~Job() = default;

public:
static WPEFramework::Core::ProxyType<WPEFramework::Core::IDispatch> Create(Async& parent, const string& method, const DispatchFunction lambda, void* usercb);

void Dispatch() override
{
_lambda(_parent, _usercb);
}

private:
Async& _parent;
string _method;
DispatchFunction _lambda;
void* _usercb;
};

public:
struct CallbackData {
const DispatchFunction lambda;
WPEFramework::Core::ProxyType<WPEFramework::Core::IDispatch> job;
uint32_t id;
};

using CallbackMap = std::map<void*, CallbackData>;
using MethodMap = std::map<string, CallbackMap>;

private:
static constexpr uint32_t DefaultId = 0xFFFFFFFF;
static constexpr uint32_t DefaultWaitTime = WPEFramework::Core::infinite;

public:
static Async& Instance();
static void Dispose();
void Configure(Transport<WPEFramework::Core::JSON::IElement>* transport);

public:
template <typename RESPONSE, typename PARAMETERS, typename CALLBACK>
Firebolt::Error Invoke(const string& method, const PARAMETERS& parameters, const CALLBACK& callback, void* usercb, uint32_t waitTime = DefaultWaitTime)
{
Firebolt::Error status = Firebolt::Error::None;
if (_transport != nullptr) {
Transport<WPEFramework::Core::JSON::IElement>* transport = _transport;
std::function<void(void* usercb, void* response, Firebolt::Error status)> actualCallback = callback;
DispatchFunction lambda = [actualCallback, transport, method, parameters, waitTime](Async& parent, void* usercb) -> Firebolt::Error {
RESPONSE response;
uint32_t id = DefaultId;
Firebolt::Error status = transport->InvokeAsync(method, parameters, id);
if (status == Firebolt::Error::None && parent.IsActive(method, usercb) == true) {
parent.UpdateEntry(method, usercb, id);
status = transport->WaitForResponse(id, response, waitTime);
if (status == Firebolt::Error::None && parent.IsActive(method, usercb) == true) {
WPEFramework::Core::ProxyType<RESPONSE>* jsonResponse = new WPEFramework::Core::ProxyType<RESPONSE>();
*jsonResponse = WPEFramework::Core::ProxyType<RESPONSE>::Create();
(*jsonResponse)->FromString(response);
actualCallback(usercb, jsonResponse, status);
parent.RemoveEntry(method, usercb);
}

}
return (status);
};

_adminLock.Lock();
WPEFramework::Core::ProxyType<WPEFramework::Core::IDispatch> job = WPEFramework::Core::ProxyType<WPEFramework::Core::IDispatch>(WPEFramework::Core::ProxyType<Async::Job>::Create(*this, method, lambda, usercb));
CallbackData callbackData = {lambda, job, DefaultId};
MethodMap::iterator index = _methodMap.find(method);
if (index != _methodMap.end()) {
CallbackMap::iterator callbackIndex = index->second.find(usercb);
if (callbackIndex == index->second.end()) {
index->second.emplace(std::piecewise_construct, std::forward_as_tuple(usercb), std::forward_as_tuple(callbackData));
}
} else {

CallbackMap callbackMap;
callbackMap.emplace(std::piecewise_construct, std::forward_as_tuple(usercb), std::forward_as_tuple(callbackData));
_methodMap.emplace(std::piecewise_construct, std::forward_as_tuple(method), std::forward_as_tuple(callbackMap));
}
_adminLock.Unlock();

WPEFramework::Core::IWorkerPool::Instance().Submit(job);
}

return status;
}

Firebolt::Error Abort(const string& method, void* usercb)
{
RemoveEntry(method, usercb);
return (Firebolt::Error::None);
}

void UpdateEntry(const string& method, void* usercb, uint32_t id)
{
_adminLock.Lock();
MethodMap::iterator index = _methodMap.find(method);
if (index != _methodMap.end()) {
CallbackMap::iterator callbackIndex = index->second.find(usercb);
if (callbackIndex != index->second.end()) {
callbackIndex->second.id = id;
}
}
_adminLock.Unlock();
}

void RemoveEntry(const string& method, void* usercb)
{
_adminLock.Lock();
MethodMap::iterator index = _methodMap.find(method);
if (index != _methodMap.end()) {
CallbackMap::iterator callbackIndex = index->second.find(usercb);
if (callbackIndex != index->second.end()) {
if (IsValidJob(callbackIndex->second)) {
WPEFramework::Core::IWorkerPool::Instance().Revoke(callbackIndex->second.job);
}
index->second.erase(callbackIndex);
if (index->second.size() == 0) {
_methodMap.erase(index);
}
}
}
_adminLock.Unlock();
}

bool IsActive(const string& method, void* usercb)
{
bool valid = false;
_adminLock.Lock();
MethodMap::iterator index = _methodMap.find(method);
if (index != _methodMap.end()) {
CallbackMap::iterator callbackIndex = index->second.find(usercb);
if (callbackIndex != index->second.end()) {
valid = true;
}
}
_adminLock.Unlock();
return valid;
}

private:
void Clear();
inline bool IsValidJob(CallbackData& callbackData) {
return (callbackData.job.IsValid() && (callbackData.id == DefaultId));
}

private:
MethodMap _methodMap;
WPEFramework::Core::CriticalSection _adminLock;
Transport<WPEFramework::Core::JSON::IElement>* _transport;

static Async* _singleton;
};
}
1 change: 1 addition & 0 deletions languages/cpp/src/shared/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_library(${TARGET} ${FIREBOLT_LIBRARY_TYPE}
Transport/Transport.cpp
Accessor/Accessor.cpp
Event/Event.cpp
Async/Async.cpp
)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
Expand Down
16 changes: 15 additions & 1 deletion languages/cpp/src/shared/src/Event/Event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ namespace FireboltSDK {
{
Firebolt::Error status = Firebolt::Error::None;
_adminLock.Lock();
EventMap::iterator eventIndex = _eventMap.find(eventName);
EventMap::iterator eventIndex = _eventMap.begin();
if (eventIndex != _eventMap.end()) {
CallbackMap::iterator callbackIndex = eventIndex->second.find(usercb);
if (callbackIndex->second.state != State::EXECUTING) {
Expand All @@ -146,4 +146,18 @@ namespace FireboltSDK {

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);
}
eventIndex = _eventMap.erase(eventIndex);
}
_adminLock.Unlock();
}

}
1 change: 1 addition & 0 deletions languages/cpp/src/shared/src/Event/Event.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ namespace FireboltSDK {
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;

Expand Down
1 change: 1 addition & 0 deletions languages/cpp/src/shared/src/FireboltSDK.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "Transport/Transport.h"
#include "Properties/Properties.h"
#include "Accessor/Accessor.h"
#include "Async/Async.h"
#include "Logger/Logger.h"
#include "TypesPriv.h"
#include "types.h"
Loading
Loading