* Copyright (C) 2025 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.
*/
#ifndef CALLBACK_MANAGER_H
#define CALLBACK_MANAGER_H
#include <mutex>
#include "location_napi_errcode.h"
namespace OHOS {
namespace Location {
template <typename T>
class CallbackManager {
public:
CallbackManager() = default;
virtual ~CallbackManager() = default;
bool IsCallbackInMap(const napi_env& env, const napi_value& handler);
void AddCallback(const napi_env& env, const napi_ref& handlerRef, const sptr<T>& callback);
void DeleteCallback(const napi_env& env, const napi_value& handler);
sptr<T> GetCallbackPtr(const napi_env& env, const napi_value& handler);
void DeleteCallbackByEnv(const napi_env& env);
const std::map<napi_env, std::map<napi_ref, sptr<T>>> GetCallbackMap();
bool RegCallback(const napi_env& env, const size_t argc, const napi_value* argv);
LocationErrCode SubscribeChange(const napi_env& env, const napi_ref& handlerRef, sptr<T>& callbackHost);
private:
std::map<napi_env, std::map<napi_ref, sptr<T>>> callbackMap_;
std::mutex mutex_;
};
template <typename T>
const std::map<napi_env, std::map<napi_ref, sptr<T>>> CallbackManager<T>::GetCallbackMap()
{
std::unique_lock<std::mutex> lock(mutex_);
return callbackMap_;
}
template <typename T>
void CallbackManager<T>::DeleteCallbackByEnv(const napi_env& env)
{
std::unique_lock<std::mutex> lock(mutex_);
auto iter = callbackMap_.find(env);
if (iter == callbackMap_.end()) {
return;
}
iter->second.clear();
callbackMap_.erase(iter);
}
template <typename T>
bool CallbackManager<T>::IsCallbackInMap(const napi_env& env, const napi_value& handler)
{
std::unique_lock<std::mutex> lock(mutex_);
auto iter = callbackMap_.find(env);
if (iter == callbackMap_.end()) {
return false;
}
for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) {
auto ref = innerIter->first;
if (IsCallbackEquals(env, handler, ref)) {
return true;
}
}
return false;
}
template <typename T>
void CallbackManager<T>::AddCallback(const napi_env& env, const napi_ref& handlerRef, const sptr<T>& callback)
{
std::unique_lock<std::mutex> lock(mutex_);
auto iter = callbackMap_.find(env);
if (iter == callbackMap_.end()) {
std::map<napi_ref, sptr<T>> innerMap;
innerMap.insert(std::make_pair(handlerRef, callback));
callbackMap_.insert(std::make_pair(env, innerMap));
return;
}
iter->second.insert(std::make_pair(handlerRef, callback));
}
template <typename T>
void CallbackManager<T>::DeleteCallback(const napi_env& env, const napi_value& handler)
{
std::unique_lock<std::mutex> lock(mutex_);
auto iter = callbackMap_.find(env);
if (iter == callbackMap_.end()) {
return;
}
for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) {
auto ref = innerIter->first;
if (IsCallbackEquals(env, handler, ref)) {
innerIter = iter->second.erase(innerIter);
if (iter->second.size() == 0) {
callbackMap_.erase(iter);
}
break;
}
}
}
template <typename T>
sptr<T> CallbackManager<T>::GetCallbackPtr(const napi_env& env, const napi_value& handler)
{
std::unique_lock<std::mutex> lock(mutex_);
auto iter = callbackMap_.find(env);
if (iter == callbackMap_.end()) {
return nullptr;
}
for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) {
auto ref = innerIter->first;
if (IsCallbackEquals(env, handler, ref)) {
return innerIter->second;
}
}
return nullptr;
}
template<typename T>
bool CallbackManager<T>::RegCallback(const napi_env& env, const size_t argc, const napi_value* argv)
{
if (argc != PARAM2) {
HandleSyncErrCode(env, ERRCODE_INVALID_PARAM);
return false;
}
if (!CheckIfParamIsFunctionType(env, argv[PARAM1])) {
HandleSyncErrCode(env, ERRCODE_INVALID_PARAM);
return false;
}
if (IsCallbackInMap(env, argv[PARAM1])) {
LBSLOGE(LOCATION_NAPI, "%{public}s, This request already exists", __func__);
return false;
}
auto callbackHost = sptr<T>(new (std::nothrow) T());
if (callbackHost != nullptr) {
napi_ref handlerRef = nullptr;
NAPI_CALL_BASE(env, napi_create_reference(env, argv[PARAM1], 1, &handlerRef), false);
LocationErrCode errorCode = SubscribeChange(env, handlerRef, callbackHost);
if (errorCode != ERRCODE_SUCCESS) {
HandleSyncErrCode(env, errorCode);
return false;
}
AddCallback(env, handlerRef, callbackHost);
}
return true;
}
template<typename T>
LocationErrCode CallbackManager<T>::SubscribeChange(const napi_env& env,
const napi_ref& handlerRef, sptr<T>& callbackHost)
{
callbackHost->SetEnv(env);
callbackHost->SetHandleCb(handlerRef);
return ERRCODE_SUCCESS;
}
}
}
#endif