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
22 namespace OHOS {
23 namespace Location {
24 template <typename T>
25 class CallbackManager {
26 public:
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);
37 private:
38 std::map<napi_env, std::map<napi_ref, sptr<T>>> callbackMap_;
39 std::mutex mutex_;
40 };
41
42 template <typename T>
GetCallbackMap()43 std::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
49 template <typename T>
DeleteCallbackByEnv(const napi_env & env)50 void 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
61 template <typename T>
IsCallbackInMap(const napi_env & env,const napi_value & handler)62 bool 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
78 template <typename T>
AddCallback(const napi_env & env,const napi_ref & handlerRef,const sptr<T> & callback)79 void 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
92 template <typename T>
DeleteCallback(const napi_env & env,const napi_value & handler)93 void 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
112 template <typename T>
GetCallbackPtr(const napi_env & env,const napi_value & handler)113 sptr<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
129 template<typename T>
RegCallback(const napi_env & env,const size_t argc,const napi_value * argv)130 bool 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
159 template<typename T>
SubscribeChange(const napi_env & env,const napi_ref & handlerRef,sptr<T> & callbackHost)160 LocationErrCode 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