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