1 /*
2 * Copyright (C) 2021-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 "wifi_napi_utils.h"
17 #include "securec.h"
18 #include "wifi_logger.h"
19 #include "context.h"
20 #include "wifi_napi_errcode.h"
21 #include <shared_mutex>
22
23 namespace OHOS {
24 namespace Wifi {
25 DEFINE_WIFILOG_LABEL("WifiNAPIUtils");
26
TraceFuncCall(std::string funcName)27 TraceFuncCall::TraceFuncCall(std::string funcName): m_funcName(funcName)
28 {
29 if (m_isTrace) {
30 m_startTime = std::chrono::steady_clock::now();
31 WIFI_LOGI("Call wifi func: %{public}s (start)", m_funcName.c_str());
32 }
33 }
34
~TraceFuncCall()35 TraceFuncCall::~TraceFuncCall()
36 {
37 if (m_isTrace) {
38 auto us = std::chrono::duration_cast<std::chrono::microseconds>
39 (std::chrono::steady_clock::now() - m_startTime).count();
40 constexpr int usForPerMs = 1000;
41 WIFI_LOGI("Call wifi func: %{public}s (end), time cost:%{public}lldus, %{public}lldms",
42 m_funcName.c_str(), us, us / usForPerMs);
43 }
44 }
45
UndefinedNapiValue(const napi_env & env)46 napi_value UndefinedNapiValue(const napi_env& env)
47 {
48 napi_value result;
49 napi_get_undefined(env, &result);
50 return result;
51 }
52
CreateInt32(const napi_env & env)53 napi_value CreateInt32(const napi_env& env)
54 {
55 int32_t value = 1;
56 napi_value result = nullptr;
57 napi_create_int32(env, value, &result);
58 return result;
59 }
60
JsObjectToString(const napi_env & env,const napi_value & object,const char * fieldStr,const int bufLen,std::string & fieldRef)61 napi_value JsObjectToString(const napi_env& env, const napi_value& object,
62 const char* fieldStr, const int bufLen, std::string& fieldRef)
63 {
64 bool hasProperty = false;
65 NAPI_CALL(env, napi_has_named_property(env, object, fieldStr, &hasProperty));
66 if (hasProperty) {
67 napi_value field;
68 napi_valuetype valueType;
69
70 napi_get_named_property(env, object, fieldStr, &field);
71 NAPI_CALL(env, napi_typeof(env, field, &valueType));
72 if (valueType != napi_string) {
73 WIFI_LOGE("Wrong argument type. String expected.");
74 return NULL;
75 }
76 if (bufLen <= 0) {
77 return NULL;
78 }
79 char *buf = (char *)malloc(bufLen);
80 if (buf == nullptr) {
81 WIFI_LOGE("Js object to str malloc failed");
82 return NULL;
83 }
84 if (memset_s(buf, bufLen, 0, bufLen) != EOK) {
85 free(buf);
86 buf = nullptr;
87 WIFI_LOGE("Js object memset_s is failed");
88 return NULL;
89 }
90 size_t result = 0;
91 if (napi_get_value_string_utf8(env, field, buf, bufLen, &result) != napi_ok) {
92 free(buf);
93 buf = nullptr;
94 return NULL;
95 }
96 fieldRef = buf;
97 free(buf);
98 buf = nullptr;
99 } else {
100 WIFI_LOGW("Js obj to str no property: %{public}s", fieldStr);
101 return NULL;
102 }
103 return UndefinedNapiValue(env);
104 }
105
JsObjectToInt(const napi_env & env,const napi_value & object,const char * fieldStr,int & fieldRef)106 napi_value JsObjectToInt(const napi_env& env, const napi_value& object, const char* fieldStr, int& fieldRef)
107 {
108 bool hasProperty = false;
109 NAPI_CALL(env, napi_has_named_property(env, object, fieldStr, &hasProperty));
110 if (hasProperty) {
111 napi_value field;
112 napi_valuetype valueType;
113
114 napi_get_named_property(env, object, fieldStr, &field);
115 NAPI_CALL(env, napi_typeof(env, field, &valueType));
116 NAPI_ASSERT(env, valueType == napi_number, "Wrong argument type. Number expected.");
117 auto ret = napi_get_value_int32(env, field, &fieldRef);
118 if (ret) {
119 WIFI_LOGD("[%{public}s]:%{public}d, fieldStr:%{public}s=>%{public}d.", __FUNCTION__, ret, fieldStr,
120 fieldRef);
121 }
122 } else {
123 WIFI_LOGW("Js to int no property: %{public}s", fieldStr);
124 }
125 return UndefinedNapiValue(env);
126 }
127
JsObjectToUint(const napi_env & env,const napi_value & object,const char * fieldStr,uint32_t & fieldRef)128 napi_value JsObjectToUint(const napi_env& env, const napi_value& object, const char* fieldStr, uint32_t& fieldRef)
129 {
130 bool hasProperty = false;
131 NAPI_CALL(env, napi_has_named_property(env, object, fieldStr, &hasProperty));
132 if (hasProperty) {
133 napi_value field;
134 napi_valuetype valueType;
135
136 napi_get_named_property(env, object, fieldStr, &field);
137 NAPI_CALL(env, napi_typeof(env, field, &valueType));
138 NAPI_ASSERT(env, valueType == napi_number, "Wrong argument type. Number expected.");
139 auto ret = napi_get_value_uint32(env, field, &fieldRef);
140 if (ret) {
141 WIFI_LOGD("[%{public}s]:%{public}u, fieldStr:%{public}s=>%{public}u.", __FUNCTION__, ret, fieldStr,
142 fieldRef);
143 }
144 } else {
145 WIFI_LOGW("Js to int no property: %{public}s", fieldStr);
146 }
147 return UndefinedNapiValue(env);
148 }
149
JsObjectToBool(const napi_env & env,const napi_value & object,const char * fieldStr,bool & fieldRef)150 napi_value JsObjectToBool(const napi_env& env, const napi_value& object, const char* fieldStr, bool& fieldRef)
151 {
152 bool hasProperty = false;
153 NAPI_CALL(env, napi_has_named_property(env, object, fieldStr, &hasProperty));
154 if (hasProperty) {
155 napi_value field;
156 napi_valuetype valueType;
157
158 napi_get_named_property(env, object, fieldStr, &field);
159 NAPI_CALL(env, napi_typeof(env, field, &valueType));
160 NAPI_ASSERT(env, valueType == napi_boolean, "Wrong argument type. Bool expected.");
161 napi_get_value_bool(env, field, &fieldRef);
162 } else {
163 WIFI_LOGW("Js to bool no property: %{public}s", fieldStr);
164 }
165 return UndefinedNapiValue(env);
166 }
167
JsObjectToU8Vector(const napi_env & env,const napi_value & object,const char * fieldStr)168 std::vector<uint8_t> JsObjectToU8Vector(const napi_env& env, const napi_value& object, const char* fieldStr)
169 {
170 bool hasProperty = false;
171 NAPI_CALL_BASE(env, napi_has_named_property(env, object, fieldStr, &hasProperty), {});
172 napi_value fieldValue;
173 if (!hasProperty || napi_get_named_property(env, object, fieldStr, &fieldValue) != napi_ok) {
174 WIFI_LOGW("JsObjectToU8Vector, Js to U8Vector no property: %{public}s", fieldStr);
175 return {};
176 }
177
178 bool isTypedArray = false;
179 if (napi_is_typedarray(env, fieldValue, &isTypedArray) != napi_ok || !isTypedArray) {
180 WIFI_LOGW("JsObjectToU8Vector, property is not typedarray: %{public}s", fieldStr);
181 return {};
182 }
183
184 size_t length = 0;
185 size_t offset = 0;
186 napi_typedarray_type type;
187 napi_value buffer = nullptr;
188 NAPI_CALL_BASE(env, napi_get_typedarray_info(env, fieldValue, &type, &length, nullptr, &buffer, &offset), {});
189 if (type != napi_uint8_array || buffer == nullptr) {
190 WIFI_LOGW("JsObjectToU8Vector, %{public}s, buffer is nullptr: %{public}d",
191 fieldStr, (int)(buffer == nullptr));
192 return {};
193 }
194
195 size_t total = 0;
196 uint8_t *data = nullptr;
197 NAPI_CALL_BASE(env, napi_get_arraybuffer_info(env, buffer, reinterpret_cast<void **>(&data), &total), {});
198 length = std::min<size_t>(length, total - offset);
199 std::vector<uint8_t> result(length);
200 int retCode = memcpy_s(result.data(), result.size(), &data[offset], length);
201 if (retCode != 0) {
202 WIFI_LOGW("JsObjectToU8Vector, memcpy_s return fail: %{public}d", retCode);
203 return {};
204 }
205 return result;
206 }
207
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result,size_t strLen)208 napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str,
209 napi_value& result, size_t strLen)
210 {
211 napi_value value;
212 size_t len = strLen;
213 napi_status status = napi_create_string_utf8(env, str, len, &value);
214 if (status != napi_ok) {
215 WIFI_LOGE("Set value create utf8 string error! field: %{public}s", fieldStr);
216 return status;
217 }
218 status = napi_set_named_property(env, result, fieldStr, value);
219 if (status != napi_ok) {
220 WIFI_LOGE("Set utf8 string named property error! field: %{public}s", fieldStr);
221 }
222 return status;
223 }
224
SetValueUtf8String(const napi_env & env,const std::string & fieldStr,const std::string & valueStr,napi_value & result)225 napi_status SetValueUtf8String(const napi_env& env, const std::string &fieldStr, const std::string &valueStr,
226 napi_value& result)
227 {
228 WIFI_LOGD("SetValueUtf8String, fieldStr: %{public}s, valueStr: %{public}s",
229 fieldStr.c_str(), valueStr.c_str());
230 napi_value value;
231 size_t len = valueStr.length();
232 napi_status status = napi_create_string_utf8(env, valueStr.c_str(), len, &value);
233 if (status != napi_ok) {
234 WIFI_LOGE("Set value create utf8 string error! field: %{public}s", fieldStr.c_str());
235 return status;
236 }
237 status = napi_set_named_property(env, result, fieldStr.c_str(), value);
238 if (status != napi_ok) {
239 WIFI_LOGE("Set utf8 string named property error! field: %{public}s", fieldStr.c_str());
240 }
241 return status;
242 }
243
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)244 napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
245 {
246 napi_value value;
247 napi_status status = napi_create_int32(env, intValue, &value);
248 if (status != napi_ok) {
249 WIFI_LOGE("Set value create int32 error! field: %{public}s", fieldStr);
250 return status;
251 }
252 status = napi_set_named_property(env, result, fieldStr, value);
253 if (status != napi_ok) {
254 WIFI_LOGE("Set int32 named property error! field: %{public}s", fieldStr);
255 }
256 return status;
257 }
258
SetValueUnsignedInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)259 napi_status SetValueUnsignedInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
260 {
261 napi_value value;
262 napi_status status = napi_create_uint32(env, intValue, &value);
263 if (status != napi_ok) {
264 WIFI_LOGE("Set value create unsigned int32 error! field: %{public}s", fieldStr);
265 return status;
266 }
267 status = napi_set_named_property(env, result, fieldStr, value);
268 if (status != napi_ok) {
269 WIFI_LOGE("Set unsigned int32 named property error! field: %{public}s", fieldStr);
270 }
271 return status;
272 }
273
SetValueInt64(const napi_env & env,const char * fieldStr,const int64_t intValue,napi_value & result)274 napi_status SetValueInt64(const napi_env& env, const char* fieldStr, const int64_t intValue, napi_value& result)
275 {
276 napi_value value;
277 napi_status status = napi_create_int64(env, intValue, &value);
278 if (status != napi_ok) {
279 WIFI_LOGE("Set value create int64 error! field: %{public}s", fieldStr);
280 return status;
281 }
282 status = napi_set_named_property(env, result, fieldStr, value);
283 if (status != napi_ok) {
284 WIFI_LOGE("Set int64 named property error! field: %{public}s", fieldStr);
285 }
286 return status;
287 }
288
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)289 napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
290 {
291 napi_value value;
292 napi_status status = napi_get_boolean(env, boolvalue, &value);
293 if (status != napi_ok) {
294 WIFI_LOGE("Set value create boolean error! field: %{public}s", fieldStr);
295 return status;
296 }
297 status = napi_set_named_property(env, result, fieldStr, value);
298 if (status != napi_ok) {
299 WIFI_LOGE("Set boolean named property error! field: %{public}s", fieldStr);
300 }
301 return status;
302 }
303
SetValueU8Vector(const napi_env & env,const char * fieldStr,const std::vector<uint8_t> value,napi_value & result)304 napi_status SetValueU8Vector(const napi_env& env, const char* fieldStr,
305 const std::vector<uint8_t> value, napi_value& result)
306 {
307 napi_value array;
308 napi_status status = napi_create_array_with_length(env, value.size(), &array);
309 if (status != napi_ok) {
310 WIFI_LOGE("failed to create array! field: %{public}s", fieldStr);
311 return status;
312 }
313 std::vector<uint8_t> vec = value;
314 for (auto i = 0; i < vec.size(); ++i) {
315 napi_value value;
316 napi_status status = napi_create_int32(env, vec[i], &value);
317 if (status != napi_ok) {
318 WIFI_LOGE("failed to create int32!");
319 return status;
320 }
321 status = napi_set_element(env, array, i, value);
322 if (status != napi_ok) {
323 WIFI_LOGE("failed to set element, status: %{public}d", status);
324 return status;
325 }
326 }
327 if (napi_set_named_property(env, result, fieldStr, array) != napi_ok) {
328 WIFI_LOGE("failed to set %{public}s named property!", fieldStr);
329 }
330 return status;
331 }
332
InitAsyncCallBackEnv(const napi_env & env,AsyncContext * asyncContext,const size_t argc,const napi_value * argv,const size_t nonCallbackArgNum)333 static napi_value InitAsyncCallBackEnv(const napi_env& env, AsyncContext *asyncContext,
334 const size_t argc, const napi_value *argv, const size_t nonCallbackArgNum)
335 {
336 for (size_t i = nonCallbackArgNum; i != argc; ++i) {
337 napi_valuetype valuetype;
338 NAPI_CALL(env, napi_typeof(env, argv[i], &valuetype));
339 NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
340 napi_create_reference(env, argv[i], 1, &asyncContext->callback[i - nonCallbackArgNum]);
341 }
342 return nullptr;
343 }
344
InitAsyncPromiseEnv(const napi_env & env,AsyncContext * asyncContext,napi_value & promise)345 static napi_value InitAsyncPromiseEnv(const napi_env& env, AsyncContext *asyncContext, napi_value& promise)
346 {
347 napi_deferred deferred;
348 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
349 asyncContext->deferred = deferred;
350 return nullptr;
351 }
352
DoCallBackAsyncWork(const napi_env & env,AsyncContext * asyncContext)353 static napi_value DoCallBackAsyncWork(const napi_env& env, AsyncContext *asyncContext)
354 {
355 napi_create_async_work(
356 env,
357 nullptr,
358 asyncContext->resourceName,
359 [](napi_env env, void* data) {
360 if (data == nullptr) {
361 WIFI_LOGE("Async data parameter is null");
362 return;
363 }
364 AsyncContext *context = (AsyncContext *)data;
365 context->executeFunc(context);
366 },
367 [](napi_env env, napi_status status, void* data) {
368 if (data == nullptr) {
369 WIFI_LOGE("Async data parameter is null");
370 return;
371 }
372 AsyncContext *context = (AsyncContext *)data;
373 context->completeFunc(data);
374 HandleCallbackErrCode(env, *context);
375 if (context->callback[0] != nullptr) {
376 napi_delete_reference(env, context->callback[0]);
377 }
378 if (context->callback[1] != nullptr) {
379 napi_delete_reference(env, context->callback[1]);
380 }
381 napi_delete_async_work(env, context->work);
382 delete context;
383 },
384 (void *)asyncContext,
385 &asyncContext->work);
386 NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated));
387 return UndefinedNapiValue(env);
388 }
389
DoPromiseAsyncWork(const napi_env & env,AsyncContext * asyncContext)390 static napi_value DoPromiseAsyncWork(const napi_env& env, AsyncContext *asyncContext)
391 {
392 napi_create_async_work(
393 env,
394 nullptr,
395 asyncContext->resourceName,
396 [](napi_env env, void *data) {
397 if (data == nullptr) {
398 WIFI_LOGE("Async data parameter is null");
399 return;
400 }
401 AsyncContext *context = (AsyncContext *)data;
402 context->executeFunc(context);
403 },
404 [](napi_env env, napi_status status, void *data) {
405 if (data == nullptr) {
406 WIFI_LOGE("Async data parameter is null");
407 return;
408 }
409 AsyncContext *context = (AsyncContext *)data;
410 if (!context->waitCallback) {
411 context->completeFunc(data);
412 HandlePromiseErrCode(env, *context);
413 napi_delete_async_work(env, context->work);
414 delete context;
415 } else {
416 napi_delete_async_work(env, context->work);
417 context->completeFunc(data);
418 }
419 },
420 (void *)asyncContext,
421 &asyncContext->work);
422 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
423 return UndefinedNapiValue(env);
424 }
425
DoAsyncWork(const napi_env & env,AsyncContext * asyncContext,const size_t argc,const napi_value * argv,const size_t nonCallbackArgNum)426 napi_value DoAsyncWork(const napi_env& env, AsyncContext *asyncContext,
427 const size_t argc, const napi_value *argv, const size_t nonCallbackArgNum)
428 {
429 if (argc > nonCallbackArgNum) {
430 InitAsyncCallBackEnv(env, asyncContext, argc, argv, nonCallbackArgNum);
431 return DoCallBackAsyncWork(env, asyncContext);
432 } else {
433 napi_value promise;
434 InitAsyncPromiseEnv(env, asyncContext, promise);
435 DoPromiseAsyncWork(env, asyncContext);
436 return promise;
437 }
438 }
SetNamedPropertyByInteger(napi_env env,napi_value dstObj,int32_t objName,const char * propName)439 void SetNamedPropertyByInteger(napi_env env, napi_value dstObj, int32_t objName, const char *propName)
440 {
441 napi_value prop = nullptr;
442 if (napi_create_int32(env, objName, &prop) == napi_ok) {
443 napi_set_named_property(env, dstObj, propName, prop);
444 }
445 }
446
447 static std::shared_mutex g_asyncContextMutex;
448 static std::map<NapiAsyncType, AsyncContext *> g_asyncContextMap;
449
TryPushAsyncContext(NapiAsyncType type,AsyncContext * asyncContext)450 bool TryPushAsyncContext(NapiAsyncType type, AsyncContext *asyncContext)
451 {
452 if (asyncContext == nullptr) {
453 WIFI_LOGE("asyncContext is nullptr!");
454 return false;
455 }
456
457 std::unique_lock<std::shared_mutex> guard(g_asyncContextMutex);
458 auto it = g_asyncContextMap.find(type);
459 if (it != g_asyncContextMap.end()) {
460 WIFI_LOGE("Async context(%{public}d) hasn't been triggered!", static_cast<int>(type));
461 return false;
462 }
463
464 g_asyncContextMap[type] = asyncContext;
465 return true;
466 }
467
EraseAsyncContext(NapiAsyncType type)468 void EraseAsyncContext(NapiAsyncType type)
469 {
470 std::unique_lock<std::shared_mutex> guard(g_asyncContextMutex);
471 g_asyncContextMap.erase(type);
472 }
473
GetAsyncContext(NapiAsyncType type)474 AsyncContext *GetAsyncContext(NapiAsyncType type)
475 {
476 std::shared_lock<std::shared_mutex> guard(g_asyncContextMutex);
477 auto it = g_asyncContextMap.find(type);
478 return it != g_asyncContextMap.end() ? it->second : nullptr;
479 }
480
481 } // namespace Wifi
482 } // namespace OHOS
483