Skip to content

Commit

Permalink
CPPSDK : Add Async communication support and CPP code generation for …
Browse files Browse the repository at this point in the history
…x-uses + x-allow-focus=true (#170)
  • Loading branch information
HaseenaSainul authored Mar 19, 2024
1 parent 2f7017a commit d79396f
Show file tree
Hide file tree
Showing 17 changed files with 455 additions and 43 deletions.
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

0 comments on commit d79396f

Please sign in to comment.