• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 #include "country_code_callback_napi.h"
17 
18 #include "common_utils.h"
19 #include "ipc_skeleton.h"
20 #include "location_log.h"
21 #include "napi/native_api.h"
22 #include "country_code.h"
23 #include "napi_util.h"
24 
25 namespace OHOS {
26 namespace Location {
27 static std::mutex g_regCallbackMutex;
28 static std::vector<napi_ref> g_registerCallbacks;
CountryCodeCallbackNapi()29 CountryCodeCallbackNapi::CountryCodeCallbackNapi()
30 {
31     env_ = nullptr;
32     handlerCb_ = nullptr;
33 }
34 
~CountryCodeCallbackNapi()35 CountryCodeCallbackNapi::~CountryCodeCallbackNapi()
36 {
37     LBSLOGW(COUNTRY_CODE_CALLBACK, "~CountryCodeCallbackNapi()");
38 }
39 
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)40 int CountryCodeCallbackNapi::OnRemoteRequest(
41     uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
42 {
43     LBSLOGD(COUNTRY_CODE_CALLBACK, "CountryCodeCallbackNapi::OnRemoteRequest!");
44     if (data.ReadInterfaceToken() != GetDescriptor()) {
45         LBSLOGE(COUNTRY_CODE_CALLBACK, "invalid token.");
46         return -1;
47     }
48 
49     switch (code) {
50         case COUNTRY_CODE_CHANGE_EVENT: {
51             auto countryCodePtr = CountryCode::Unmarshalling(data);
52             OnCountryCodeChange(countryCodePtr);
53             break;
54         }
55         default: {
56             IPCObjectStub::OnRemoteRequest(code, data, reply, option);
57             break;
58         }
59     }
60     return 0;
61 }
62 
FindCountryCodeCallback(napi_ref cb)63 bool FindCountryCodeCallback(napi_ref cb)
64 {
65     std::unique_lock<std::mutex> guard(g_regCallbackMutex);
66     auto iter = std::find(g_registerCallbacks.begin(), g_registerCallbacks.end(), cb);
67     if (iter == g_registerCallbacks.end()) {
68         return false;
69     }
70     return true;
71 }
72 
DeleteCountryCodeCallback(napi_ref cb)73 void DeleteCountryCodeCallback(napi_ref cb)
74 {
75     std::unique_lock<std::mutex> guard(g_regCallbackMutex);
76     for (auto iter = g_registerCallbacks.begin(); iter != g_registerCallbacks.end(); iter++) {
77         if (*iter == cb) {
78             iter = g_registerCallbacks.erase(iter);
79             break;
80         }
81     }
82     LBSLOGW(COUNTRY_CODE_CALLBACK, "after DeleteCountryCodeCallback, callback size %{public}s",
83         std::to_string(g_registerCallbacks.size()).c_str());
84 }
85 
Send(const std::shared_ptr<CountryCode> & country)86 bool CountryCodeCallbackNapi::Send(const std::shared_ptr<CountryCode>& country)
87 {
88     std::unique_lock<std::mutex> guard(mutex_);
89     uv_loop_s *loop = nullptr;
90     if (env_ == nullptr) {
91         LBSLOGE(COUNTRY_CODE_CALLBACK, "env_ == nullptr.");
92         return false;
93     }
94     if (handlerCb_ == nullptr) {
95         LBSLOGE(COUNTRY_CODE_CALLBACK, "handler is nullptr.");
96         return false;
97     }
98     if (country == nullptr) {
99         LBSLOGE(COUNTRY_CODE_CALLBACK, "country == nullptr.");
100         return false;
101     }
102     NAPI_CALL_BASE(env_, napi_get_uv_event_loop(env_, &loop), false);
103     if (loop == nullptr) {
104         LBSLOGE(COUNTRY_CODE_CALLBACK, "loop == nullptr.");
105         return false;
106     }
107     uv_work_t *work = new (std::nothrow) uv_work_t;
108     if (work == nullptr) {
109         LBSLOGE(COUNTRY_CODE_CALLBACK, "work == nullptr.");
110         return false;
111     }
112     auto context = new (std::nothrow) CountryCodeContext(env_);
113     if (context == nullptr) {
114         LBSLOGE(COUNTRY_CODE_CALLBACK, "context == nullptr.");
115         delete work;
116         return false;
117     }
118     if (!InitContext(context)) {
119         LBSLOGE(COUNTRY_CODE_CALLBACK, "InitContext fail");
120         delete work;
121         delete context;
122         return false;
123     }
124     context->country = country;
125     work->data = context;
126     UvQueueWork(loop, work);
127     return true;
128 }
129 
UvQueueWork(uv_loop_s * loop,uv_work_t * work)130 void CountryCodeCallbackNapi::UvQueueWork(uv_loop_s* loop, uv_work_t* work)
131 {
132     uv_queue_work(
133         loop,
134         work,
135         [](uv_work_t *work) {},
136         [](uv_work_t *work, int status) {
137             CountryCodeContext *context = nullptr;
138             napi_handle_scope scope = nullptr;
139             if (work == nullptr) {
140                 LBSLOGE(COUNTRY_CODE_CALLBACK, "work is nullptr!");
141                 return;
142             }
143             context = static_cast<CountryCodeContext *>(work->data);
144             if (context == nullptr || context->env == nullptr) {
145                 LBSLOGE(COUNTRY_CODE_CALLBACK, "context is nullptr!");
146                 delete work;
147                 return;
148             }
149             NAPI_CALL_RETURN_VOID(context->env, napi_open_handle_scope(context->env, &scope));
150             if (scope == nullptr) {
151                 LBSLOGE(COUNTRY_CODE_CALLBACK, "scope is nullptr");
152                 delete context;
153                 delete work;
154                 return;
155             }
156             napi_value jsEvent;
157             CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_create_object(context->env, &jsEvent),
158                 scope, context, work);
159             if (context->country) {
160                 CountryCodeToJs(context->env, context->country, jsEvent);
161             } else {
162                 LBSLOGE(LOCATOR_STANDARD, "country is nullptr!");
163             }
164             if (context->callback[0] != nullptr) {
165                 napi_value undefine;
166                 napi_value handler = nullptr;
167                 napi_status ret = napi_ok;
168                 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
169                     napi_get_undefined(context->env, &undefine), scope, context, work);
170                 if (FindCountryCodeCallback(context->callback[0])) {
171                     CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
172                         napi_get_reference_value(context->env, context->callback[SUCCESS_CALLBACK], &handler),
173                         scope, context, work);
174                     ret = napi_call_function(context->env, nullptr, handler, 1, &jsEvent, &undefine);
175                 } else {
176                     LBSLOGE(COUNTRY_CODE_CALLBACK, "no valid callback");
177                 }
178                 if (ret != napi_ok) {
179                     LBSLOGE(COUNTRY_CODE_CALLBACK, "Report event failed");
180                 }
181             }
182             NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
183             delete context;
184             delete work;
185     });
186 }
187 
OnCountryCodeChange(const std::shared_ptr<CountryCode> & country)188 void CountryCodeCallbackNapi::OnCountryCodeChange(const std::shared_ptr<CountryCode>& country)
189 {
190     LBSLOGD(COUNTRY_CODE_CALLBACK, "CountryCodeCallbackNapi::OnCountryCodeChange");
191     Send(country);
192 }
193 
SetEnv(napi_env env)194 void CountryCodeCallbackNapi::SetEnv(napi_env env)
195 {
196     std::unique_lock<std::mutex> guard(mutex_);
197     env_ = env;
198 }
199 
SetCallback(napi_ref cb)200 void CountryCodeCallbackNapi::SetCallback(napi_ref cb)
201 {
202     {
203         std::unique_lock<std::mutex> guard(mutex_);
204         handlerCb_ = cb;
205     }
206     std::unique_lock<std::mutex> guard(g_regCallbackMutex);
207     g_registerCallbacks.emplace_back(cb);
208 }
209 
DeleteHandler()210 void CountryCodeCallbackNapi::DeleteHandler()
211 {
212     std::unique_lock<std::mutex> guard(mutex_);
213     if (handlerCb_ == nullptr || env_ == nullptr) {
214         LBSLOGE(COUNTRY_CODE_CALLBACK, "handler or env is nullptr.");
215         return;
216     }
217     DeleteCountryCodeCallback(handlerCb_);
218     NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, handlerCb_));
219     handlerCb_ = nullptr;
220 }
221 }  // namespace Location
222 }  // namespace OHOS
223