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