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 #include <uv.h>
17 #include <functional>
18 #include "scan_callback.h"
19 #include "napi_scan_utils.h"
20 #include "scan_log.h"
21
22 namespace OHOS::Scan {
ScanCallback(napi_env env,napi_ref ref)23 ScanCallback::ScanCallback(napi_env env, napi_ref ref) : env_(env), ref_(ref), callbackFunction_(nullptr)
24 {
25 }
26
ScanCallback(std::function<void (std::vector<ScanDeviceInfo> & infos)> callbackFunction)27 ScanCallback::ScanCallback(std::function<void(std::vector<ScanDeviceInfo> &infos)>
28 callbackFunction) : env_(nullptr), ref_(nullptr), callbackFunction_(callbackFunction)
29 {
30 }
31
~ScanCallback()32 ScanCallback::~ScanCallback()
33 {
34 std::lock_guard<std::mutex> autoLock(mutex_);
35 if (env_ == nullptr || ref_ == nullptr) {
36 return;
37 }
38 SCAN_HILOGI("callback has been destroyed");
39 uv_loop_s *loop = nullptr;
40 napi_get_uv_event_loop(env_, &loop);
41 if (loop == nullptr) {
42 return;
43 }
44 Param *param = new (std::nothrow) Param;
45 if (param == nullptr) {
46 return;
47 }
48 param->env = env_;
49 param->callbackRef = ref_;
50 uv_work_t *work = new (std::nothrow) uv_work_t;
51 if (work == nullptr) {
52 delete param;
53 return;
54 }
55 work->data = reinterpret_cast<void*>(param);
56 int retVal = UvQueueWork(loop, work);
57 if (retVal != 0) {
58 SCAN_HILOGE("Failed to get uv_queue_work.");
59 delete param;
60 delete work;
61 return;
62 }
63 }
64
InitialCallbackParam(napi_env & env_,napi_ref & ref_,std::mutex & mutex_)65 void CallbackParam::InitialCallbackParam(napi_env &env_, napi_ref &ref_, std::mutex &mutex_)
66 {
67 std::lock_guard<std::mutex> lock(mutex_);
68 this->env = env_;
69 this->ref = ref_;
70 this->mutexPtr = &mutex_;
71 }
72
SetCallbackParam(uint32_t & state,const ScanDeviceInfoTCP & deviceInfoTCP)73 void CallbackParam::SetCallbackParam(uint32_t &state, const ScanDeviceInfoTCP &deviceInfoTCP)
74 {
75 std::lock_guard<std::mutex> lock(*mutexPtr);
76 this->state = state;
77 this->deviceInfoTCP = deviceInfoTCP;
78 }
79
SetCallbackParam(uint32_t & state,const ScanDeviceInfo & deviceInfo)80 void CallbackParam::SetCallbackParam(uint32_t &state, const ScanDeviceInfo &deviceInfo)
81 {
82 std::lock_guard<std::mutex> lock(*mutexPtr);
83 this->state = state;
84 this->deviceInfo = deviceInfo;
85 }
86
SetCallbackSyncParam(uint32_t & state,const ScanDeviceInfoSync & deviceInfoSync)87 void CallbackParam::SetCallbackSyncParam(uint32_t &state, const ScanDeviceInfoSync &deviceInfoSync)
88 {
89 std::lock_guard<std::mutex> lock(*mutexPtr);
90 this->state = state;
91 this->deviceInfoSync = deviceInfoSync;
92 }
93
SetCallbackParam(bool & isGetSucc,int32_t & sizeRead)94 void CallbackParam::SetCallbackParam(bool &isGetSucc, int32_t &sizeRead)
95 {
96 std::lock_guard<std::mutex> lock(*mutexPtr);
97 this->isGetSucc = isGetSucc;
98 this->sizeRead = sizeRead;
99 }
100
SetCallbackParam(int32_t & scanVersion)101 void CallbackParam::SetCallbackParam(int32_t &scanVersion)
102 {
103 std::lock_guard<std::mutex> lock(*mutexPtr);
104 this->scanVersion = scanVersion;
105 }
106
SetCallbackParam(std::string & message)107 void CallbackParam::SetCallbackParam(std::string &message)
108 {
109 std::lock_guard<std::mutex> lock(*mutexPtr);
110 this->message = message;
111 }
112
SetCallbackContext(CallbackParam * & callBackParam,uv_work_function & uvWorkLambda,std::mutex & mutex_)113 void CallbackContext::SetCallbackContext(CallbackParam* &callBackParam,
114 uv_work_function &uvWorkLambda, std::mutex &mutex_)
115 {
116 std::lock_guard<std::mutex> lock(mutex_);
117 this->callBackParam = callBackParam;
118 this->uvWorkLambda = uvWorkLambda;
119 }
120
CreateCallbackParam(uv_work_t * & work,CallbackParam * & param,CallbackContext * & context,bool & flag)121 void ScanCallback::CreateCallbackParam(uv_work_t *&work, CallbackParam *¶m, CallbackContext *&context, bool &flag)
122 {
123 work = new (std::nothrow) uv_work_t;
124 CHECK_AND_CREATE(work, "Failed to create uv_work_t work", flag);
125 param = new (std::nothrow) CallbackParam;
126 CHECK_AND_CREATE(param, "Failed to create CallbackParam param", flag);
127 context = new (std::nothrow) CallbackContext;
128 CHECK_AND_CREATE(context, "Failed to create CallbackContext context", flag);
129 if (!flag) {
130 DELETE_AND_NULLIFY(work);
131 DELETE_AND_NULLIFY(param);
132 DELETE_AND_NULLIFY(context);
133 }
134 }
135
ExecuteUvQueueWork(CallbackContext * & context,uv_work_t * & work,uv_loop_s * & loop)136 bool ScanCallback::ExecuteUvQueueWork(CallbackContext* &context, uv_work_t* &work, uv_loop_s *&loop)
137 {
138 work->data = context;
139 int32_t retVal = uv_queue_work(
140 loop, work, [](uv_work_t *work) {},
141 [](uv_work_t *work, int statusInt) {
142 CallbackContext *context = static_cast<CallbackContext*>(work->data);
143 CallbackParam *cbParam = context->callBackParam;
144 napi_handle_scope scope = nullptr;
145 napi_open_handle_scope(cbParam->env, &scope);
146 if (scope != nullptr) {
147 auto uvWorkLambda = context->uvWorkLambda;
148 std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
149 napi_value callbackFunc = NapiScanUtils::GetReference(cbParam->env, cbParam->ref);
150 napi_value callbackResult = nullptr;
151 uvWorkLambda(cbParam, callbackFunc, callbackResult);
152 SCAN_HILOGD("run napi call deviceInfo callback fun success");
153 napi_close_handle_scope(cbParam->env, scope);
154 }
155 DELETE_AND_NULLIFY(work);
156 DELETE_AND_NULLIFY(cbParam);
157 DELETE_AND_NULLIFY(context);
158 });
159 if (retVal != 0) {
160 SCAN_HILOGE("failed to get uv_queue_work.");
161 DELETE_AND_NULLIFY(work);
162 DELETE_AND_NULLIFY(context->callBackParam);
163 DELETE_AND_NULLIFY(context);
164 return false;
165 }
166 return true;
167 }
168
OnCallback(uint32_t state,const ScanDeviceInfoTCP & info)169 bool ScanCallback::OnCallback(uint32_t state, const ScanDeviceInfoTCP &info)
170 {
171 SCAN_HILOGD("Enter OnCallback::ScanDeviceInfoTCP");
172
173 INIT_CALLBACK_PARAMS;
174
175 if (!flag) {
176 SCAN_HILOGE("ScanCallback::OnCallback ScanDeviceInfoTCP error exit");
177 return false;
178 }
179
180 uv_work_function uvWorkLambda = [](CallbackParam* &cbParam, napi_value &callbackFunc, napi_value &callbackResult) {
181 napi_value callbackValues[NapiScanUtils::ARGC_ONE] = { 0 };
182 callbackValues[0] = ScannerInfoHelperTCP::MakeJsObject(cbParam->env, cbParam->deviceInfoTCP);
183 napi_call_function(cbParam->env, nullptr, callbackFunc,
184 NapiScanUtils::ARGC_ONE, callbackValues, &callbackResult);
185 };
186 param->InitialCallbackParam(env_, ref_, mutex_);
187 param->SetCallbackParam(state, info);
188 context->SetCallbackContext(param, uvWorkLambda, mutex_);
189
190 return ExecuteUvQueueWork(context, work, loop);
191 }
192
OnCallback(uint32_t state,const ScanDeviceInfo & info)193 bool ScanCallback::OnCallback(uint32_t state, const ScanDeviceInfo &info)
194 {
195 SCAN_HILOGD("Enter OnCallback::ScanDeviceInfo");
196
197 INIT_CALLBACK_PARAMS;
198
199 if (!flag) {
200 SCAN_HILOGE("ScanCallback::OnCallback ScanDeviceInfo error exit");
201 return false;
202 }
203
204 uv_work_function uvWorkLambda = [](CallbackParam* &cbParam, napi_value &callbackFunc, napi_value &callbackResult) {
205 napi_value callbackValues[NapiScanUtils::ARGC_ONE] = { 0 };
206 callbackValues[0] = ScannerInfoHelper::MakeJsObject(cbParam->env, cbParam->deviceInfo);
207 napi_call_function(cbParam->env, nullptr, callbackFunc, NapiScanUtils::ARGC_ONE,
208 callbackValues, &callbackResult);
209 };
210 param->InitialCallbackParam(env_, ref_, mutex_);
211 param->SetCallbackParam(state, info);
212 context->SetCallbackContext(param, uvWorkLambda, mutex_);
213
214 return ExecuteUvQueueWork(context, work, loop);
215 }
216
OnCallbackSync(uint32_t state,const ScanDeviceInfoSync & info)217 bool ScanCallback::OnCallbackSync(uint32_t state, const ScanDeviceInfoSync &info)
218 {
219 SCAN_HILOGD("Enter OnCallback::ScanDeviceInfo");
220
221 INIT_CALLBACK_PARAMS;
222
223 if (!flag) {
224 SCAN_HILOGE("ScanCallback::OnCallback ScanDeviceInfo error exit");
225 return false;
226 }
227
228 uv_work_function uvWorkLambda = [](CallbackParam* &cbParam, napi_value &callbackFunc, napi_value &callbackResult) {
229 napi_value callbackValues[NapiScanUtils::ARGC_ONE] = { 0 };
230 callbackValues[0] = ScannerInfoSyncHelper::MakeJsObject(cbParam->env, cbParam->deviceInfoSync);
231 napi_call_function(cbParam->env, nullptr, callbackFunc, NapiScanUtils::ARGC_ONE,
232 callbackValues, &callbackResult);
233 };
234 param->InitialCallbackParam(env_, ref_, mutex_);
235 param->SetCallbackSyncParam(state, info);
236 context->SetCallbackContext(param, uvWorkLambda, mutex_);
237
238 return ExecuteUvQueueWork(context, work, loop);
239 }
240
OnGetFrameResCallback(bool isGetSucc,int32_t sizeRead)241 bool ScanCallback::OnGetFrameResCallback(bool isGetSucc, int32_t sizeRead)
242 {
243 SCAN_HILOGD("Enter OnCallback::OnGetFrameResCallback");
244
245 INIT_CALLBACK_PARAMS;
246
247 if (!flag) {
248 SCAN_HILOGE("ScanCallback::OnCallback OnGetFrameResCallback error exit");
249 return false;
250 }
251
252 uv_work_function uvWorkLambda = [](CallbackParam* &cbParam, napi_value &callbackFunc, napi_value &callbackResult) {
253 napi_value callbackValues[NapiScanUtils::ARGC_TWO] = { 0 };
254 callbackValues[0] = NapiScanUtils::CreateBoolean(cbParam->env, cbParam->isGetSucc);
255 callbackValues[1] = NapiScanUtils::CreateInt32(cbParam->env, cbParam->sizeRead);
256 napi_call_function(cbParam->env, nullptr, callbackFunc, NapiScanUtils::ARGC_TWO,
257 callbackValues, &callbackResult);
258 };
259 param->InitialCallbackParam(env_, ref_, mutex_);
260 param->SetCallbackParam(isGetSucc, sizeRead);
261 context->SetCallbackContext(param, uvWorkLambda, mutex_);
262
263 return ExecuteUvQueueWork(context, work, loop);
264 }
265
OnScanInitCallback(int32_t & scanVersion)266 bool ScanCallback::OnScanInitCallback(int32_t &scanVersion)
267 {
268 SCAN_HILOGD("Enter OnCallback::OnScanInitCallback");
269
270 INIT_CALLBACK_PARAMS;
271
272 if (!flag) {
273 SCAN_HILOGE("ScanCallback::OnCallback OnScanInitCallback error exit");
274 return false;
275 }
276
277 uv_work_function uvWorkLambda = [](CallbackParam* &cbParam, napi_value &callbackFunc, napi_value &callbackResult) {
278 napi_value callbackValues[NapiScanUtils::ARGC_ONE] = { 0 };
279 callbackValues[0] = NapiScanUtils::CreateInt32(cbParam->env, cbParam->scanVersion);
280 napi_call_function(cbParam->env, nullptr, callbackFunc, NapiScanUtils::ARGC_ONE,
281 callbackValues, &callbackResult);
282 };
283 param->InitialCallbackParam(env_, ref_, mutex_);
284 param->SetCallbackParam(scanVersion);
285 context->SetCallbackContext(param, uvWorkLambda, mutex_);
286
287 return ExecuteUvQueueWork(context, work, loop);
288 }
289
OnSendSearchMessage(std::string & message)290 bool ScanCallback::OnSendSearchMessage(std::string &message)
291 {
292 SCAN_HILOGD("Enter OnCallback::OnSendSearchMessage");
293
294 INIT_CALLBACK_PARAMS;
295
296 if (!flag) {
297 SCAN_HILOGE("ScanCallback::OnCallback OnSendSearchMessage error exit");
298 return false;
299 }
300
301 uv_work_function uvWorkLambda = [](CallbackParam* &cbParam, napi_value &callbackFunc, napi_value &callbackResult) {
302 napi_value callbackValues[NapiScanUtils::ARGC_ONE] = { 0 };
303 callbackValues[0] = NapiScanUtils::CreateStringUtf8(cbParam->env, cbParam->message);
304 napi_call_function(cbParam->env, nullptr, callbackFunc, NapiScanUtils::ARGC_ONE,
305 callbackValues, &callbackResult);
306 };
307 param->InitialCallbackParam(env_, ref_, mutex_);
308 param->SetCallbackParam(message);
309 context->SetCallbackContext(param, uvWorkLambda, mutex_);
310
311 return ExecuteUvQueueWork(context, work, loop);
312 }
313
OnGetDevicesList(std::vector<ScanDeviceInfo> & infos)314 bool ScanCallback::OnGetDevicesList(std::vector<ScanDeviceInfo> &infos)
315 {
316 SCAN_HILOGI("Enter OnGetDevicesList");
317 if (callbackFunction_ == nullptr) {
318 SCAN_HILOGE("callbackFunction_ is a nullptr");
319 return false;
320 }
321 callbackFunction_(infos);
322 return true;
323 }
324
UvQueueWork(uv_loop_s * loop,uv_work_t * work)325 int ScanCallback::UvQueueWork(uv_loop_s *loop, uv_work_t *work)
326 {
327 if (loop == nullptr || work == nullptr) {
328 return -1; // parameter error
329 }
330 int retVal = uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int status) {
331 SCAN_HILOGI("uv_queue_work ScanCallback DeleteReference");
332 if (work == nullptr) {
333 return;
334 }
335 Param *param = reinterpret_cast<Param*>(work->data);
336 if (param == nullptr) {
337 delete work;
338 return;
339 }
340 napi_handle_scope scope = nullptr;
341 napi_open_handle_scope(param->env, &scope);
342 if (scope == nullptr) {
343 delete param;
344 delete work;
345 return;
346 }
347 napi_ref callbackRef = param->callbackRef;
348 NapiScanUtils::DeleteReference(param->env, callbackRef);
349 napi_close_handle_scope(param->env, scope);
350 delete param;
351 delete work;
352 });
353 return retVal;
354 }
355 } // namespace OHOS::Scan
356