/* * Copyright (C) 2020 MERA * * 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. */ #include "ClientManager.h" #include "hmi-debug.h" #include #include // static void ClientManager::cbRemoveClientCtx(void *data) { ClientManager::instance().removeClient((ClientManager::ClientCtx*)data); } // static ClientManager& ClientManager::instance() { static ClientManager instance; return instance; } ClientManager::~ClientManager() { std::lock_guard lock(this->m_mutex); for (auto cl : m_clients) delete cl.second; } ClientManager::ClientCtx* ClientManager::addClient(afb_req_t req, const std::string& appid) { ClientCtx* ctx = (ClientCtx*)afb_req_context_get(req); if (!ctx) { HMI_NOTICE("cloudproxy-service", "create new session for %s", appid.c_str()); ctx = new ClientCtx{appid, afb_api_make_event(req->api, appid.c_str())}; afb_req_session_set_LOA(req, 1); afb_req_context_set(req, ctx, cbRemoveClientCtx); } m_clients[appid] = ctx; return ctx; } void ClientManager::removeClient(ClientCtx* ctx) { if(!ctx) { HMI_ERROR("cloudproxy-service", "data is nullptr"); return; } HMI_NOTICE("cloudproxy-service", "remove app %s", ctx->appid.c_str()); std::lock_guard lock(this->m_mutex); auto it = m_clients.find(ctx->appid); if (it != m_clients.end()) { delete it->second; m_clients.erase(it); } } bool ClientManager::handleRequest(afb_req_t request, const std::string& verb, const std::string& appid) { HMI_NOTICE("cloudproxy-service", "handleRequest: verb='%s', appid='%s'", verb.c_str(), appid.c_str()); std::lock_guard lock(this->m_mutex); if (appid.empty()) { HMI_ERROR("cloudproxy-service", "appid is empty"); return false; } auto client_it = m_clients.find(appid); if (verb != "subscribe" && client_it == m_clients.end()) { HMI_NOTICE("cloudproxy-service", "client with appid '%s' is not registered", appid.c_str()); return false; } if (verb == "subscribe") { const char *value = afb_req_value(request, "event"); if(!value) { HMI_ERROR("cloudproxy-service", "Can't subscribe: event name is not defined"); return false; } std::string req_event{value}; HMI_NOTICE("cloudproxy-service", "subscribe req: appid '%s', event '%s'", appid.c_str(), req_event.c_str()); if (!isSupportedEvent(req_event)) { HMI_ERROR("cloudproxy-service", "event '%s' is not supported", req_event.c_str()); return false; } ClientCtx* ctx = addClient(request, appid); ctx->subs_events.insert(req_event); if(!ctx->subscription) { if(afb_req_subscribe(request, ctx->event) == 0) { ctx->subscription = true; } else { HMI_ERROR("cloudproxy-service", "API error in afb_req_subscribe"); return false; } } return true; } else if (verb == "unsubscribe") { const char *value = afb_req_value(request, "event"); if(!value) { HMI_ERROR("cloudproxy-service", "Can't unsubscribe: event name is not defined"); return false; } std::string req_event{value}; HMI_NOTICE("cloudproxy-service", "unsubscribe req: appid '%s', event '%s'", appid.c_str(), req_event.c_str()); ClientCtx* ctx{client_it->second}; ctx->subs_events.erase(req_event); if(ctx->subs_events.empty()) { if (afb_req_unsubscribe(request, ctx->event) != 0) HMI_ERROR("cloudproxy-service", "API error in afb_req_unsubscribe"); ctx->subscription = false; } return true; } HMI_NOTICE("cloudproxy-service", "Unsupported verb '%s'", verb.c_str()); return false; } bool ClientManager::isSupportedEvent(const std::string& event) { const std::set event_list{ "sendMessageConfirmation", "receivedMessage" }; return (event_list.end() != event_list.find(event)); } bool ClientManager::emitReceivedMessage(const std::string& appid, const std::string& data) { std::lock_guard lock(this->m_mutex); auto it = m_clients.find(appid); if (it == m_clients.end()) { HMI_WARNING("cloudproxy-service", "Client with appid '%s' is not present in list", appid.c_str()); // print app list for (const auto& i : m_clients) HMI_DEBUG("cloudproxy-service", "Client list: appid '%s' - '%s'", i.first.c_str(), i.second->appid.c_str()); return false; } json_object* push_obj = json_object_new_object(); json_object_object_add(push_obj, "type", json_object_new_string("receivedMessage")); json_object_object_add(push_obj, "data", json_object_new_string(data.c_str())); return (0 == afb_event_push(it->second->event, push_obj)); } bool ClientManager::emitSendMessageConfirmation(const std::string& appid, bool result) { std::lock_guard lock(this->m_mutex); auto it = m_clients.find(appid); if (it == m_clients.end()) { HMI_WARNING("cloudproxy-service", "Client with appid '%s' is not present in list", appid.c_str()); // print app list for (const auto& i : m_clients) HMI_DEBUG("cloudproxy-service", "Client list: appid '%s' - '%s'", i.first.c_str(), i.second->appid.c_str()); return false; } json_object* push_obj = json_object_new_object(); json_object_object_add(push_obj, "type", json_object_new_string("sendMessageConfirmation")); json_object_object_add(push_obj, "result", json_object_new_boolean(result)); return (0 == afb_event_push(it->second->event, push_obj)); }