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