• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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