ea0dc20a创建于 2023年7月4日历史提交
/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * 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 <uv.h>

#include "client_helper.h"
#include "node_api.h"

#include "update_define.h"
#include "update_helper.h"
#include "update_session.h"
#include "session_manager.h"

using namespace std;

namespace OHOS {
namespace UpdateEngine {
SessionManager::SessionManager(napi_env env, napi_ref thisReference) : env_(env), thisReference_(thisReference) {}

SessionManager::~SessionManager()
{
    Clear();
}

void SessionManager::AddSession(std::shared_ptr<IUpdateSession> session)
{
    PARAM_CHECK(session != nullptr, return, "Invalid param");
#ifndef UPDATER_API_TEST
    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
#endif
    sessions_.insert(make_pair(session->GetSessionId(), session));
}

void SessionManager::RemoveSession(uint32_t sessionId)
{
    CLIENT_LOGI("RemoveSession sess");
#ifndef UPDATER_API_TEST
    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
#endif
    sessions_.erase(sessionId);
}

void SessionManager::Clear()
{
    {
        std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
        sessions_.clear();
    }
    if (thisReference_ != nullptr) {
        napi_delete_reference(env_, thisReference_);
    }
}

bool SessionManager::GetFirstSessionId(uint32_t &sessionId)
{
#ifndef UPDATER_API_TEST
    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
#endif
    {
        if (sessions_.empty()) {
            return false;
        }
        sessionId = sessions_.begin()->second->GetSessionId();
        return true;
    }
}

bool SessionManager::GetNextSessionId(uint32_t &sessionId)
{
#ifndef UPDATER_API_TEST
    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
#endif
    {
        auto iter = sessions_.find(sessionId);
        if (iter == sessions_.end()) {
            return false;
        }
        iter++;
        if (iter == sessions_.end()) {
            return false;
        }
        sessionId = iter->second->GetSessionId();
    }
    return true;
}

int32_t SessionManager::ProcessUnsubscribe(const std::string &eventType, size_t argc, napi_value arg)
{
    napi_handle_scope scope;
    napi_status status = napi_open_handle_scope(env_, &scope);
    PARAM_CHECK(status == napi_ok, return -1, "Error open handle");

    uint32_t nextSessId = 0;
    bool hasNext = GetFirstSessionId(nextSessId);
    while (hasNext) {
        uint32_t currSessId = nextSessId;
        auto iter = sessions_.find(currSessId);
        if (iter == sessions_.end()) {
            break;
        }
        hasNext = GetNextSessionId(nextSessId);

        UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
        if (listener->GetType() != SessionType::SESSION_SUBSCRIBE ||
            eventType.compare(listener->GetEventType()) != 0) {
            continue;
        }
        CLIENT_LOGI("ProcessUnsubscribe remove session");
        if (argc == 1) {
            listener->RemoveHandlerRef(env_);
            RemoveSession(currSessId);
        } else if (listener->CheckEqual(env_, arg, eventType)) {
            listener->RemoveHandlerRef(env_);
            RemoveSession(currSessId);
            break;
        }
    }
    napi_close_handle_scope(env_, scope);
    return 0;
}

void SessionManager::Unsubscribe(const EventClassifyInfo &eventClassifyInfo, napi_value handle)
{
    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
    for (auto iter = sessions_.begin(); iter != sessions_.end();) {
        if (iter->second == nullptr) {
            iter = sessions_.erase(iter); // erase nullptr
            continue;
        }

        if (iter->second->GetType() != SessionType::SESSION_SUBSCRIBE) {
            ++iter;
            continue;
        }

        auto listener = static_cast<UpdateListener *>(iter->second.get());
        if (handle == nullptr && listener->IsSubscribeEvent(eventClassifyInfo)) {
            CLIENT_LOGI("Unsubscribe, remove session %{public}d without handle", listener->GetSessionId());
            iter = sessions_.erase(iter);
            continue;
        }

        if (listener->IsSameListener(env_, eventClassifyInfo, handle)) {
            CLIENT_LOGI("Unsubscribe, remove session %{public}d", listener->GetSessionId());
            iter = sessions_.erase(iter);
            continue;
        }

        ++iter;
    }
}

IUpdateSession *SessionManager::FindSessionByHandle(napi_env env, const std::string &eventType, napi_value arg)
{
    uint32_t nextSessId = 0;
    bool hasNext = GetFirstSessionId(nextSessId);
    while (hasNext) {
        uint32_t currSessId = nextSessId;
        auto iter = sessions_.find(currSessId);
        if (iter == sessions_.end()) {
            break;
        }
        hasNext = GetNextSessionId(nextSessId);

        UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
        if (listener->GetType() != SessionType::SESSION_SUBSCRIBE) {
            continue;
        }
        if ((eventType.compare(listener->GetEventType()) == 0) && listener->CheckEqual(env_, arg, eventType)) {
            return listener;
        }
    }
    return nullptr;
}

IUpdateSession *SessionManager::FindSessionByHandle(napi_env env, const EventClassifyInfo &eventClassifyInfo,
    napi_value arg)
{
    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
    for (auto &iter : sessions_) {
        if (iter.second == nullptr) {
            continue;
        }

        if (iter.second->GetType() != SessionType::SESSION_SUBSCRIBE) {
            continue;
        }

        auto listener = static_cast<UpdateListener *>(iter.second.get());
        if (listener->IsSameListener(env, eventClassifyInfo, arg)) {
            return listener;
        }
    }
    return nullptr;
}

void SessionManager::PublishToJS(const EventClassifyInfo &eventClassifyInfo, const EventInfo &eventInfo)
{
    napi_handle_scope scope;
    napi_status status = napi_open_handle_scope(env_, &scope);
    PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error open_handle_scope");
    napi_value thisVar = nullptr;
    status = napi_get_reference_value(env_, thisReference_, &thisVar);
    PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, napi_close_handle_scope(env_, scope); return,
        "Error get_reference");

    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
    for (auto &iter : sessions_) {
        if (iter.second == nullptr) {
            continue;
        }

        if (iter.second->GetType() != SessionType::SESSION_SUBSCRIBE) {
            continue;
        }

        UpdateListener *listener = static_cast<UpdateListener *>(iter.second.get());
        if (!listener->IsSubscribeEvent(eventClassifyInfo)) {
            continue;
        }

        listener->NotifyJS(env_, thisVar, eventInfo);
    }
    napi_close_handle_scope(env_, scope);
}

void SessionManager::Emit(const std::string &type, const BusinessError &businessError)
{
    CLIENT_LOGI("SessionManager::Emit %{public}s", type.c_str());
    std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
    uint32_t nextSessId = 0;
    bool hasNext = GetFirstSessionId(nextSessId);
    while (hasNext) {
        uint32_t currSessId = nextSessId;
        auto iter = sessions_.find(currSessId);
        if (iter == sessions_.end()) {
            break;
        }
        hasNext = GetNextSessionId(nextSessId);
        if (iter->second == nullptr) {
            CLIENT_LOGE("SessionManager::Emit error, updateSession is null, %{public}d", iter->first);
            continue;
        }
        IUpdateSession *updateSession = (iter->second).get();
        CLIENT_LOGI("SessionManager::Emit GetType %{public}d", updateSession->GetType());
        if (updateSession->IsAsyncCompleteWork()) {
            updateSession->OnAsyncComplete(businessError);
        } else {
            CLIENT_LOGI("SessionManager::Emit GetType unknown type");
        }
    }
}

void SessionManager::Emit(const EventClassifyInfo &eventClassifyInfo, const EventInfo &eventInfo)
{
    CLIENT_LOGI("SessionManager::Emit 0x%{public}x", CAST_INT(eventClassifyInfo.eventClassify));
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    PARAM_CHECK(loop != nullptr, return, "get event loop failed.");

    using UvWorkData = std::tuple<SessionManager*, EventClassifyInfo, EventInfo>;
    UvWorkData *data = new (std::nothrow) std::tuple(this, eventClassifyInfo, eventInfo);
    PARAM_CHECK(data != nullptr, return, "alloc data failed.");

    uv_work_t *work = new (std::nothrow) uv_work_t;
    PARAM_CHECK(work != nullptr, delete data; return, "alloc work failed.");

    work->data = static_cast<void *>(data);
    uv_queue_work_with_qos(
        loop,
        work,
        [](uv_work_t *work) {},
        [](uv_work_t *work, int status) {
            UvWorkData *data = static_cast<UvWorkData*>(work->data);
            auto &[mgr, eventClassifyInfo, eventInfo] = *data;
            mgr->PublishToJS(eventClassifyInfo, eventInfo);
            delete data;
            delete work;
        },
        uv_qos_default);
}
} // namespace UpdateEngine
} // namespace OHOS