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