1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#ifndef CALLBACK_MANAGER_H 17#define CALLBACK_MANAGER_H 18 19#include <mutex> 20#include "location_napi_errcode.h" 21 22namespace OHOS { 23namespace Location { 24template <typename T> 25class CallbackManager { 26public: 27 CallbackManager() = default; 28 virtual ~CallbackManager() = default; 29 bool IsCallbackInMap(const napi_env& env, const napi_value& handler); 30 void AddCallback(const napi_env& env, const napi_ref& handlerRef, const sptr<T>& callback); 31 void DeleteCallback(const napi_env& env, const napi_value& handler); 32 sptr<T> GetCallbackPtr(const napi_env& env, const napi_value& handler); 33 void DeleteCallbackByEnv(const napi_env& env); 34 std::map<napi_env, std::map<napi_ref, sptr<T>>> GetCallbackMap(); 35 bool RegCallback(const napi_env& env, const size_t argc, const napi_value* argv); 36 LocationErrCode SubscribeChange(const napi_env& env, const napi_ref& handlerRef, sptr<T>& callbackHost); 37private: 38 std::map<napi_env, std::map<napi_ref, sptr<T>>> callbackMap_; 39 std::mutex mutex_; 40}; 41 42template <typename T> 43std::map<napi_env, std::map<napi_ref, sptr<T>>> CallbackManager<T>::GetCallbackMap() 44{ 45 std::unique_lock<std::mutex> lock(mutex_); 46 return callbackMap_; 47} 48 49template <typename T> 50void CallbackManager<T>::DeleteCallbackByEnv(const napi_env& env) 51{ 52 std::unique_lock<std::mutex> lock(mutex_); 53 auto iter = callbackMap_.find(env); 54 if (iter == callbackMap_.end()) { 55 return; 56 } 57 iter->second.clear(); 58 callbackMap_.erase(iter); 59} 60 61template <typename T> 62bool CallbackManager<T>::IsCallbackInMap(const napi_env& env, const napi_value& handler) 63{ 64 std::unique_lock<std::mutex> lock(mutex_); 65 auto iter = callbackMap_.find(env); 66 if (iter == callbackMap_.end()) { 67 return false; 68 } 69 for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) { 70 auto ref = innerIter->first; 71 if (IsCallbackEquals(env, handler, ref)) { 72 return true; 73 } 74 } 75 return false; 76} 77 78template <typename T> 79void CallbackManager<T>::AddCallback(const napi_env& env, const napi_ref& handlerRef, const sptr<T>& callback) 80{ 81 std::unique_lock<std::mutex> lock(mutex_); 82 auto iter = callbackMap_.find(env); 83 if (iter == callbackMap_.end()) { 84 std::map<napi_ref, sptr<T>> innerMap; 85 innerMap.insert(std::make_pair(handlerRef, callback)); 86 callbackMap_.insert(std::make_pair(env, innerMap)); 87 return; 88 } 89 iter->second.insert(std::make_pair(handlerRef, callback)); 90} 91 92template <typename T> 93void CallbackManager<T>::DeleteCallback(const napi_env& env, const napi_value& handler) 94{ 95 std::unique_lock<std::mutex> lock(mutex_); 96 auto iter = callbackMap_.find(env); 97 if (iter == callbackMap_.end()) { 98 return; 99 } 100 for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) { 101 auto ref = innerIter->first; 102 if (IsCallbackEquals(env, handler, ref)) { 103 innerIter = iter->second.erase(innerIter); 104 if (iter->second.size() == 0) { 105 callbackMap_.erase(iter); 106 } 107 break; 108 } 109 } 110} 111 112template <typename T> 113sptr<T> CallbackManager<T>::GetCallbackPtr(const napi_env& env, const napi_value& handler) 114{ 115 std::unique_lock<std::mutex> lock(mutex_); 116 auto iter = callbackMap_.find(env); 117 if (iter == callbackMap_.end()) { 118 return nullptr; 119 } 120 for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) { 121 auto ref = innerIter->first; 122 if (IsCallbackEquals(env, handler, ref)) { 123 return innerIter->second; 124 } 125 } 126 return nullptr; 127} 128 129template<typename T> 130bool CallbackManager<T>::RegCallback(const napi_env& env, const size_t argc, const napi_value* argv) 131{ 132 if (argc != PARAM2) { 133 HandleSyncErrCode(env, ERRCODE_INVALID_PARAM); 134 return false; 135 } 136 if (!CheckIfParamIsFunctionType(env, argv[PARAM1])) { 137 HandleSyncErrCode(env, ERRCODE_INVALID_PARAM); 138 return false; 139 } 140 if (IsCallbackInMap(env, argv[PARAM1])) { 141 LBSLOGE(LOCATION_NAPI, "%{public}s, This request already exists", __func__); 142 return false; 143 } 144 auto callbackHost = sptr<T>(new (std::nothrow) T()); 145 if (callbackHost != nullptr) { 146 napi_ref handlerRef = nullptr; 147 NAPI_CALL_BASE(env, napi_create_reference(env, argv[PARAM1], 1, &handlerRef), false); 148 149 LocationErrCode errorCode = SubscribeChange(env, handlerRef, callbackHost); 150 if (errorCode != ERRCODE_SUCCESS) { 151 HandleSyncErrCode(env, errorCode); 152 return false; 153 } 154 AddCallback(env, handlerRef, callbackHost); 155 } 156 return true; 157} 158 159template<typename T> 160LocationErrCode CallbackManager<T>::SubscribeChange(const napi_env& env, 161 const napi_ref& handlerRef, sptr<T>& callbackHost) 162{ 163 callbackHost->SetEnv(env); 164 callbackHost->SetHandleCb(handlerRef); 165 return ERRCODE_SUCCESS; 166} 167} // namespace Location 168} // namespace OHOS 169#endif // CALLBACK_MANAGER_H 170