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 namespace OHOS {
22 namespace Location {
23 template <typename T>
24 class CallbackManager {
25 public:
26 CallbackManager() = default;
27 virtual ~CallbackManager() = default;
28 bool IsCallbackInMap(const napi_env& env, const napi_value& handler);
29 void AddCallback(const napi_env& env, const napi_ref& handlerRef, const sptr<T>& callback);
30 void DeleteCallback(const napi_env& env, const napi_value& handler);
31 sptr<T> GetCallbackPtr(const napi_env& env, const napi_value& handler);
32 void DeleteCallbackByEnv(const napi_env& env);
33 std::map<napi_env, std::map<napi_ref, sptr<T>>> GetCallbackMap();
34 bool RegCallback(const napi_env& env, const size_t argc, const napi_value* argv);
35 LocationErrCode SubscribeChange(const napi_env& env, const napi_ref& handlerRef, sptr<T>& callbackHost);
36 private:
37 std::map<napi_env, std::map<napi_ref, sptr<T>>> callbackMap_;
38 std::mutex mutex_;
39 };
40
41 template <typename T>
GetCallbackMap()42 std::map<napi_env, std::map<napi_ref, sptr<T>>> CallbackManager<T>::GetCallbackMap()
43 {
44 std::unique_lock<std::mutex> lock(mutex_);
45 return callbackMap_;
46 }
47
48 template <typename T>
DeleteCallbackByEnv(const napi_env & env)49 void CallbackManager<T>::DeleteCallbackByEnv(const napi_env& env)
50 {
51 std::unique_lock<std::mutex> lock(mutex_);
52 auto iter = callbackMap_.find(env);
53 if (iter == callbackMap_.end()) {
54 return;
55 }
56 iter->second.clear();
57 callbackMap_.erase(iter);
58 }
59
60 template <typename T>
IsCallbackInMap(const napi_env & env,const napi_value & handler)61 bool CallbackManager<T>::IsCallbackInMap(const napi_env& env, const napi_value& handler)
62 {
63 std::unique_lock<std::mutex> lock(mutex_);
64 auto iter = callbackMap_.find(env);
65 if (iter == callbackMap_.end()) {
66 return false;
67 }
68 for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) {
69 auto ref = innerIter->first;
70 if (IsCallbackEquals(env, handler, ref)) {
71 return true;
72 }
73 }
74 return false;
75 }
76
77 template <typename T>
AddCallback(const napi_env & env,const napi_ref & handlerRef,const sptr<T> & callback)78 void CallbackManager<T>::AddCallback(const napi_env& env, const napi_ref& handlerRef, const sptr<T>& callback)
79 {
80 std::unique_lock<std::mutex> lock(mutex_);
81 auto iter = callbackMap_.find(env);
82 if (iter == callbackMap_.end()) {
83 std::map<napi_ref, sptr<T>> innerMap;
84 innerMap.insert(std::make_pair(handlerRef, callback));
85 callbackMap_.insert(std::make_pair(env, innerMap));
86 return;
87 }
88 iter->second.insert(std::make_pair(handlerRef, callback));
89 }
90
91 template <typename T>
DeleteCallback(const napi_env & env,const napi_value & handler)92 void CallbackManager<T>::DeleteCallback(const napi_env& env, const napi_value& handler)
93 {
94 std::unique_lock<std::mutex> lock(mutex_);
95 auto iter = callbackMap_.find(env);
96 if (iter == callbackMap_.end()) {
97 return;
98 }
99 for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) {
100 auto ref = innerIter->first;
101 if (IsCallbackEquals(env, handler, ref)) {
102 innerIter = iter->second.erase(innerIter);
103 if (iter->second.size() == 0) {
104 callbackMap_.erase(iter);
105 }
106 break;
107 }
108 }
109 }
110
111 template <typename T>
GetCallbackPtr(const napi_env & env,const napi_value & handler)112 sptr<T> CallbackManager<T>::GetCallbackPtr(const napi_env& env, const napi_value& handler)
113 {
114 std::unique_lock<std::mutex> lock(mutex_);
115 auto iter = callbackMap_.find(env);
116 if (iter == callbackMap_.end()) {
117 return nullptr;
118 }
119 for (auto innerIter = iter->second.begin(); innerIter != iter->second.end(); innerIter++) {
120 auto ref = innerIter->first;
121 if (IsCallbackEquals(env, handler, ref)) {
122 return innerIter->second;
123 }
124 }
125 return nullptr;
126 }
127
128 template<typename T>
RegCallback(const napi_env & env,const size_t argc,const napi_value * argv)129 bool CallbackManager<T>::RegCallback(const napi_env& env, const size_t argc, const napi_value* argv)
130 {
131 if (argc != PARAM2) {
132 HandleSyncErrCode(env, ERRCODE_INVALID_PARAM);
133 return false;
134 }
135 if (!CheckIfParamIsFunctionType(env, argv[PARAM1])) {
136 HandleSyncErrCode(env, ERRCODE_INVALID_PARAM);
137 return false;
138 }
139 if (IsCallbackInMap(env, argv[PARAM1])) {
140 LBSLOGE(LOCATION_NAPI, "%{public}s, This request already exists", __func__);
141 return false;
142 }
143 auto callbackHost = sptr<T>(new (std::nothrow) T());
144 if (callbackHost != nullptr) {
145 napi_ref handlerRef = nullptr;
146 NAPI_CALL_BASE(env, napi_create_reference(env, argv[PARAM1], 1, &handlerRef), false);
147
148 LocationErrCode errorCode = SubscribeChange(env, handlerRef, callbackHost);
149 if (errorCode != ERRCODE_SUCCESS) {
150 HandleSyncErrCode(env, errorCode);
151 return false;
152 }
153 AddCallback(env, handlerRef, callbackHost);
154 }
155 return true;
156 }
157
158 template<typename T>
SubscribeChange(const napi_env & env,const napi_ref & handlerRef,sptr<T> & callbackHost)159 LocationErrCode CallbackManager<T>::SubscribeChange(const napi_env& env,
160 const napi_ref& handlerRef, sptr<T>& callbackHost)
161 {
162 callbackHost->SetEnv(env);
163 callbackHost->SetHandleCb(handlerRef);
164 return ERRCODE_SUCCESS;
165 }
166 } // namespace Location
167 } // namespace OHOS
168 #endif // CALLBACK_MANAGER_H
169