• 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 "napi_utils.h"
17 
18 #include <algorithm>
19 #include <cmath>
20 #include <cstdlib>
21 #include <cstring>
22 #include <initializer_list>
23 #include <memory>
24 #include <new>
25 #include <string>
26 #include <map>
27 #include <vector>
28 
29 #include "base_context.h"
30 #include "cJSON.h"
31 #include "napi/native_api.h"
32 #include "napi/native_common.h"
33 #include "netstack_log.h"
34 #include "node_api.h"
35 
36 namespace OHOS::NetStack::NapiUtils {
37 static constexpr const char *GLOBAL_JSON = "JSON";
38 
39 static constexpr const char *GLOBAL_JSON_STRINGIFY = "stringify";
40 
41 static constexpr const char *GLOBAL_JSON_PARSE = "parse";
42 
43 static constexpr const char *CODE = "code";
44 
45 static constexpr const char *MSG = "message";
46 
47 static std::mutex g_mutex;
48 static std::map<uint64_t, std::shared_ptr<UvHandlerQueue>> g_handlerQueueMap;
49 static const char *const HTTP_UV_SYNC_QUEUE_NAME = "HTTP_UV_SYNC_QUEUE_NAME";
50 
51 static std::unordered_set<napi_env> unorderedSetEnv;
52 static std::mutex mutexForEnv;
53 
54 class WorkData {
55 public:
56     WorkData() = delete;
57 
WorkData(napi_env env,void * data,void (* handler)(napi_env env,napi_status status,void * data))58     WorkData(napi_env env, void *data, void (*handler)(napi_env env, napi_status status, void *data))
59         : env_(env), data_(data), handler_(handler)
60     {
61     }
62 
63     napi_env env_;
64     void *data_;
65     void (*handler_)(napi_env env, napi_status status, void *data);
66 };
67 
GetValueType(napi_env env,napi_value value)68 napi_valuetype GetValueType(napi_env env, napi_value value)
69 {
70     if (value == nullptr) {
71         return napi_undefined;
72     }
73 
74     napi_valuetype valueType = napi_undefined;
75     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
76     return valueType;
77 }
78 
IsInstanceOf(napi_env env,napi_value object,const std::string & name)79 bool IsInstanceOf(napi_env env, napi_value object, const std::string &name)
80 {
81     if (GetValueType(env, object) != napi_object) {
82         return false;
83     }
84 
85     auto global = GetGlobal(env);
86     napi_value constructor = GetNamedProperty(env, global, name);
87     if (GetValueType(env, constructor) == napi_undefined) {
88         return false;
89     }
90 
91     bool isInstance = false;
92     NAPI_CALL_BASE(env, napi_instanceof(env, object, constructor, &isInstance), false);
93     return isInstance;
94 }
95 
96 /* named property */
HasNamedProperty(napi_env env,napi_value object,const std::string & propertyName)97 bool HasNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
98 {
99     if (GetValueType(env, object) != napi_object) {
100         return false;
101     }
102 
103     bool hasProperty = false;
104     NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
105     return hasProperty;
106 }
107 
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)108 napi_value GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
109 {
110     if (GetValueType(env, object) != napi_object) {
111         return GetUndefined(env);
112     }
113 
114     napi_value value = nullptr;
115     NAPI_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
116     return value;
117 }
118 
SetNamedProperty(napi_env env,napi_value object,const std::string & name,napi_value value)119 void SetNamedProperty(napi_env env, napi_value object, const std::string &name, napi_value value)
120 {
121     if (GetValueType(env, object) != napi_object) {
122         return;
123     }
124 
125     napi_set_named_property(env, object, name.c_str(), value);
126 }
127 
GetPropertyNames(napi_env env,napi_value object)128 std::vector<std::string> GetPropertyNames(napi_env env, napi_value object)
129 {
130     if (GetValueType(env, object) != napi_object) {
131         return {};
132     }
133 
134     std::vector<std::string> ret;
135     napi_value names = nullptr;
136     NAPI_CALL_BASE(env, napi_get_property_names(env, object, &names), ret);
137     uint32_t length = 0;
138     NAPI_CALL_BASE(env, napi_get_array_length(env, names, &length), ret);
139     for (uint32_t index = 0; index < length; ++index) {
140         napi_value name = nullptr;
141         if (napi_get_element(env, names, index, &name) != napi_ok) {
142             continue;
143         }
144         if (GetValueType(env, name) != napi_string) {
145             continue;
146         }
147         ret.emplace_back(GetStringFromValueUtf8(env, name));
148     }
149     return ret;
150 }
151 
152 /* UINT32 */
CreateUint32(napi_env env,uint32_t code)153 napi_value CreateUint32(napi_env env, uint32_t code)
154 {
155     napi_value value = nullptr;
156     if (napi_create_uint32(env, code, &value) != napi_ok) {
157         return nullptr;
158     }
159     return value;
160 }
161 
162 /* UINT64 */
CreateUint64(napi_env env,uint64_t code)163 napi_value CreateUint64(napi_env env, uint64_t code)
164 {
165     napi_value value = nullptr;
166     if (napi_create_bigint_uint64(env, code, &value) != napi_ok) {
167         return nullptr;
168     }
169     return value;
170 }
171 
GetInt64FromValue(napi_env env,napi_value value)172 int64_t GetInt64FromValue(napi_env env, napi_value value)
173 {
174     if (GetValueType(env, value) != napi_number) {
175         return 0;
176     }
177     int64_t ret = 0;
178     NAPI_CALL_BASE(env, napi_get_value_int64(env, value, &ret), 0);
179     return ret;
180 }
181 
GetInt64Property(napi_env env,napi_value object,const std::string & propertyName)182 int64_t GetInt64Property(napi_env env, napi_value object, const std::string &propertyName)
183 {
184     if (!HasNamedProperty(env, object, propertyName)) {
185         return 0;
186     }
187     napi_value value = GetNamedProperty(env, object, propertyName);
188     return GetInt64FromValue(env, value);
189 }
190 
GetUint32FromValue(napi_env env,napi_value value)191 uint32_t GetUint32FromValue(napi_env env, napi_value value)
192 {
193     if (GetValueType(env, value) != napi_number) {
194         return 0;
195     }
196 
197     uint32_t ret = 0;
198     NAPI_CALL_BASE(env, napi_get_value_uint32(env, value, &ret), 0);
199     return ret;
200 }
201 
GetUint32Property(napi_env env,napi_value object,const std::string & propertyName)202 uint32_t GetUint32Property(napi_env env, napi_value object, const std::string &propertyName)
203 {
204     if (!HasNamedProperty(env, object, propertyName)) {
205         return 0;
206     }
207     napi_value value = GetNamedProperty(env, object, propertyName);
208     return GetUint32FromValue(env, value);
209 }
210 
SetUint32Property(napi_env env,napi_value object,const std::string & name,uint32_t value)211 void SetUint32Property(napi_env env, napi_value object, const std::string &name, uint32_t value)
212 {
213     napi_value jsValue = CreateUint32(env, value);
214     if (GetValueType(env, jsValue) != napi_number) {
215         return;
216     }
217 
218     napi_set_named_property(env, object, name.c_str(), jsValue);
219 }
220 
SetUint64Property(napi_env env,napi_value object,const std::string & name,uint64_t value)221 void SetUint64Property(napi_env env, napi_value object, const std::string &name, uint64_t value)
222 {
223     napi_value jsValue = CreateUint64(env, value);
224     if (GetValueType(env, jsValue) != napi_bigint) {
225         return;
226     }
227 
228     napi_set_named_property(env, object, name.c_str(), jsValue);
229 }
230 
231 /* INT32 */
CreateInt32(napi_env env,int32_t code)232 napi_value CreateInt32(napi_env env, int32_t code)
233 {
234     napi_value value = nullptr;
235     if (napi_create_int32(env, code, &value) != napi_ok) {
236         return nullptr;
237     }
238     return value;
239 }
240 
GetInt32FromValue(napi_env env,napi_value value)241 int32_t GetInt32FromValue(napi_env env, napi_value value)
242 {
243     if (GetValueType(env, value) != napi_number) {
244         return 0;
245     }
246 
247     int32_t ret = 0;
248     NAPI_CALL_BASE(env, napi_get_value_int32(env, value, &ret), 0);
249     return ret;
250 }
251 
GetInt32Property(napi_env env,napi_value object,const std::string & propertyName)252 int32_t GetInt32Property(napi_env env, napi_value object, const std::string &propertyName)
253 {
254     if (!HasNamedProperty(env, object, propertyName)) {
255         return 0;
256     }
257     napi_value value = GetNamedProperty(env, object, propertyName);
258     return GetInt32FromValue(env, value);
259 }
260 
SetInt32Property(napi_env env,napi_value object,const std::string & name,int32_t value)261 void SetInt32Property(napi_env env, napi_value object, const std::string &name, int32_t value)
262 {
263     napi_value jsValue = CreateInt32(env, value);
264     if (GetValueType(env, jsValue) != napi_number) {
265         return;
266     }
267 
268     napi_set_named_property(env, object, name.c_str(), jsValue);
269 }
270 
SetDoubleProperty(napi_env env,napi_value object,const std::string & name,double value)271 void SetDoubleProperty(napi_env env, napi_value object, const std::string &name, double value)
272 {
273     napi_value jsValue;
274     if (napi_create_double(env, value, &jsValue) != napi_ok) {
275         return;
276     }
277     if (GetValueType(env, jsValue) != napi_number) {
278         return;
279     }
280     napi_set_named_property(env, object, name.c_str(), jsValue);
281 }
282 
283 /* String UTF8 */
CreateStringUtf8(napi_env env,const std::string & str)284 napi_value CreateStringUtf8(napi_env env, const std::string &str)
285 {
286     napi_value value = nullptr;
287     if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
288         return nullptr;
289     }
290     return value;
291 }
292 
GetSecureDataPropertyUtf8(napi_env env,napi_value object,const std::string & propertyName,SecureData & data)293 void GetSecureDataPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName,
294                                SecureData &data)
295 {
296     if (!HasNamedProperty(env, object, propertyName)) {
297         return;
298     }
299     napi_value value = GetNamedProperty(env, object, propertyName);
300     GetSecureDataFromValueUtf8(env, value, data);
301 }
302 
GetSecureDataFromValueUtf8(napi_env env,napi_value value,SecureData & data)303 void GetSecureDataFromValueUtf8(napi_env env, napi_value value, SecureData &data)
304 {
305     if (GetValueType(env, value) != napi_string) {
306         return;
307     }
308 
309     size_t stringLength = 0;
310     NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength));
311     if (stringLength == 0 || stringLength > SIZE_MAX - 1) {
312         return;
313     }
314 
315     auto deleter = [](char *s) { free(reinterpret_cast<void *>(s)); };
316     auto mem = malloc(stringLength + 1);
317     if (mem == nullptr) {
318         return;
319     }
320     std::unique_ptr<char, decltype(deleter)> str(static_cast<char *>(mem), deleter);
321     if (memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
322         return;
323     }
324     size_t length = 0;
325     NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length));
326     if (length > 0) {
327         data.append(str.get(), length);
328     }
329 }
330 
GetStringFromValueUtf8(napi_env env,napi_value value)331 std::string GetStringFromValueUtf8(napi_env env, napi_value value)
332 {
333     if (GetValueType(env, value) != napi_string) {
334         return {};
335     }
336 
337     std::string result;
338     size_t stringLength = 0;
339     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength), result);
340     if (stringLength == 0) {
341         return result;
342     }
343 
344     auto deleter = [](char *s) { free(reinterpret_cast<void *>(s)); };
345     std::unique_ptr<char, decltype(deleter)> str(static_cast<char *>(malloc(stringLength + 1)), deleter);
346     if (str == nullptr || memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
347         return result;
348     }
349     size_t length = 0;
350     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length), result);
351     if (length > 0) {
352         result.append(str.get(), length);
353     }
354     return result;
355 }
356 
GetStringPropertyUtf8(napi_env env,napi_value object,const std::string & propertyName)357 std::string GetStringPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName)
358 {
359     if (!HasNamedProperty(env, object, propertyName)) {
360         return "";
361     }
362     napi_value value = GetNamedProperty(env, object, propertyName);
363     return GetStringFromValueUtf8(env, value);
364 }
365 
NapiValueToString(napi_env env,napi_value value)366 std::string NapiValueToString(napi_env env, napi_value value)
367 {
368     napi_status status;
369     napi_valuetype valueType;
370     status = napi_typeof(env, value, &valueType);
371     if (status != napi_ok) {
372         return "";
373     }
374     switch (valueType) {
375         case napi_undefined:
376         case napi_null:
377             break;
378         case napi_boolean:
379             bool boolValue;
380             status = napi_get_value_bool(env, value, &boolValue);
381             if (status == napi_ok) {
382                 return boolValue ? "true" : "false";
383             }
384             break;
385         case napi_number:
386             double doubleValue;
387             status = napi_get_value_double(env, value, &doubleValue);
388             if (status == napi_ok) {
389                 if (doubleValue == std::floor(doubleValue)) {
390                     return std::to_string(static_cast<int64_t>(doubleValue));
391                 }
392                 return std::to_string(doubleValue);
393             }
394             break;
395         case napi_string:
396             return GetStringFromValueUtf8(env, value);
397         default:
398             break;
399     }
400     return "";
401 }
402 
SetStringPropertyUtf8(napi_env env,napi_value object,const std::string & name,const std::string & value)403 void SetStringPropertyUtf8(napi_env env, napi_value object, const std::string &name, const std::string &value)
404 {
405     napi_value jsValue = CreateStringUtf8(env, value);
406     if (GetValueType(env, jsValue) != napi_string) {
407         return;
408     }
409     napi_set_named_property(env, object, name.c_str(), jsValue);
410 }
411 
412 /* array buffer */
ValueIsArrayBuffer(napi_env env,napi_value value)413 bool ValueIsArrayBuffer(napi_env env, napi_value value)
414 {
415     if (value == nullptr) {
416         return false;
417     }
418     bool isArrayBuffer = false;
419     NAPI_CALL_BASE(env, napi_is_arraybuffer(env, value, &isArrayBuffer), false);
420     return isArrayBuffer;
421 }
422 
GetInfoFromArrayBufferValue(napi_env env,napi_value value,size_t * length)423 void *GetInfoFromArrayBufferValue(napi_env env, napi_value value, size_t *length)
424 {
425     if (length == nullptr) {
426         return nullptr;
427     }
428 
429     void *data = nullptr;
430     NAPI_CALL(env, napi_get_arraybuffer_info(env, value, &data, length));
431     return data;
432 }
433 
CreateArrayBuffer(napi_env env,size_t length,void ** data)434 napi_value CreateArrayBuffer(napi_env env, size_t length, void **data)
435 {
436     if (length == 0) {
437         return nullptr;
438     }
439     napi_value result = nullptr;
440     NAPI_CALL(env, napi_create_arraybuffer(env, length, data, &result));
441     return result;
442 }
443 
444 /* object */
CreateObject(napi_env env)445 napi_value CreateObject(napi_env env)
446 {
447     napi_value object = nullptr;
448     NAPI_CALL(env, napi_create_object(env, &object));
449     return object;
450 }
451 
452 /* undefined */
GetUndefined(napi_env env)453 napi_value GetUndefined(napi_env env)
454 {
455     napi_value undefined = nullptr;
456     NAPI_CALL(env, napi_get_undefined(env, &undefined));
457     return undefined;
458 }
459 
460 /* function */
CallFunction(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv)461 napi_value CallFunction(napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv)
462 {
463     napi_value res = nullptr;
464     NAPI_CALL(env, napi_call_function(env, recv, func, argc, argv, &res));
465     return res;
466 }
467 
CreateFunction(napi_env env,const std::string & name,napi_callback func,void * arg)468 napi_value CreateFunction(napi_env env, const std::string &name, napi_callback func, void *arg)
469 {
470     napi_value res = nullptr;
471     NAPI_CALL(env, napi_create_function(env, name.c_str(), strlen(name.c_str()), func, arg, &res));
472     return res;
473 }
474 
475 /* reference */
CreateReference(napi_env env,napi_value callback)476 napi_ref CreateReference(napi_env env, napi_value callback)
477 {
478     napi_ref callbackRef = nullptr;
479     NAPI_CALL(env, napi_create_reference(env, callback, 1, &callbackRef));
480     return callbackRef;
481 }
482 
GetReference(napi_env env,napi_ref callbackRef)483 napi_value GetReference(napi_env env, napi_ref callbackRef)
484 {
485     napi_value callback = nullptr;
486     NAPI_CALL(env, napi_get_reference_value(env, callbackRef, &callback));
487     return callback;
488 }
489 
DeleteReference(napi_env env,napi_ref callbackRef)490 void DeleteReference(napi_env env, napi_ref callbackRef)
491 {
492     (void)napi_delete_reference(env, callbackRef);
493 }
494 
495 /* boolean */
GetBooleanProperty(napi_env env,napi_value object,const std::string & propertyName)496 bool GetBooleanProperty(napi_env env, napi_value object, const std::string &propertyName)
497 {
498     if (!HasNamedProperty(env, object, propertyName)) {
499         return false;
500     }
501     napi_value value = GetNamedProperty(env, object, propertyName);
502     bool ret = false;
503     NAPI_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
504     return ret;
505 }
506 
SetBooleanProperty(napi_env env,napi_value object,const std::string & name,bool value)507 void SetBooleanProperty(napi_env env, napi_value object, const std::string &name, bool value)
508 {
509     napi_value jsValue = nullptr;
510     NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, value, &jsValue));
511     if (GetValueType(env, jsValue) != napi_boolean) {
512         return;
513     }
514 
515     napi_set_named_property(env, object, name.c_str(), jsValue);
516 }
517 
GetBoolean(napi_env env,bool value)518 napi_value GetBoolean(napi_env env, bool value)
519 {
520     napi_value jsValue = nullptr;
521     NAPI_CALL(env, napi_get_boolean(env, value, &jsValue));
522     return jsValue;
523 }
524 
GetBooleanFromValue(napi_env env,napi_value value)525 bool GetBooleanFromValue(napi_env env, napi_value value)
526 {
527     if (GetValueType(env, value) != napi_boolean) {
528         return GetUndefined(env);
529     }
530 
531     bool ret = false;
532     NAPI_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
533     return ret;
534 }
535 
536 /* define properties */
DefineProperties(napi_env env,napi_value object,const std::initializer_list<napi_property_descriptor> & properties)537 void DefineProperties(napi_env env, napi_value object,
538                       const std::initializer_list<napi_property_descriptor> &properties)
539 {
540     napi_property_descriptor descriptors[properties.size()];
541     std::copy(properties.begin(), properties.end(), descriptors);
542 
543     (void)napi_define_properties(env, object, properties.size(), descriptors);
544 }
545 
546 /* array */
CreateArray(napi_env env,size_t length)547 napi_value CreateArray(napi_env env, size_t length)
548 {
549     if (length == 0) {
550         napi_value res = nullptr;
551         NAPI_CALL(env, napi_create_array(env, &res));
552         return res;
553     }
554     napi_value res = nullptr;
555     NAPI_CALL(env, napi_create_array_with_length(env, length, &res));
556     return res;
557 }
558 
SetArrayElement(napi_env env,napi_value array,uint32_t index,napi_value value)559 void SetArrayElement(napi_env env, napi_value array, uint32_t index, napi_value value)
560 {
561     (void)napi_set_element(env, array, index, value);
562 }
563 
IsArray(napi_env env,napi_value value)564 bool IsArray(napi_env env, napi_value value)
565 {
566     bool result = false;
567     NAPI_CALL_BASE(env, napi_is_array(env, value, &result), false);
568     return result;
569 }
570 
SetArrayProperty(napi_env env,napi_value object,const std::string & name,napi_value value)571 void SetArrayProperty(napi_env env, napi_value object, const std::string &name, napi_value value)
572 {
573     if (!IsArray(env, value)) {
574         return;
575     }
576     napi_set_named_property(env, object, name.c_str(), value);
577 }
578 
GetArrayLength(napi_env env,napi_value arr)579 uint32_t GetArrayLength(napi_env env, napi_value arr)
580 {
581     uint32_t arrayLength = 0;
582     NAPI_CALL_BASE(env, napi_get_array_length(env, arr, &arrayLength), 0);
583     return arrayLength;
584 }
585 
GetArrayElement(napi_env env,napi_value arr,uint32_t index)586 napi_value GetArrayElement(napi_env env, napi_value arr, uint32_t index)
587 {
588     napi_value elementValue = nullptr;
589     NAPI_CALL(env, napi_get_element(env, arr, index, &elementValue));
590     return elementValue;
591 }
592 
593 /* JSON */
JsonStringify(napi_env env,napi_value object)594 napi_value JsonStringify(napi_env env, napi_value object)
595 {
596     napi_value undefined = GetUndefined(env);
597 
598     if (GetValueType(env, object) != napi_object) {
599         return undefined;
600     }
601 
602     napi_value global = nullptr;
603     NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
604     napi_value json = nullptr;
605     NAPI_CALL_BASE(env, napi_get_named_property(env, global, GLOBAL_JSON, &json), undefined);
606     napi_value stringify = nullptr;
607     NAPI_CALL_BASE(env, napi_get_named_property(env, json, GLOBAL_JSON_STRINGIFY, &stringify), undefined);
608     if (GetValueType(env, stringify) != napi_function) {
609         return undefined;
610     }
611 
612     napi_value res = nullptr;
613     napi_value argv[1] = {object};
614     NAPI_CALL_BASE(env, napi_call_function(env, json, stringify, 1, argv, &res), undefined);
615     return res;
616 }
617 
JsonParse(napi_env env,const std::string & inStr)618 napi_value JsonParse(napi_env env, const std::string &inStr)
619 {
620     napi_value undefined = GetUndefined(env);
621     cJSON *valueJson = cJSON_Parse(inStr.c_str());
622     if (valueJson == nullptr) {
623         NETSTACK_LOGE("cJSON_Parse error");
624         return undefined;
625     }
626     cJSON_Delete(valueJson);
627 
628     auto str = NapiUtils::CreateStringUtf8(env, inStr);
629     if (GetValueType(env, str) != napi_string) {
630         return undefined;
631     }
632 
633     napi_value global = nullptr;
634     NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
635     napi_value json = nullptr;
636     NAPI_CALL_BASE(env, napi_get_named_property(env, global, GLOBAL_JSON, &json), undefined);
637     napi_value parse = nullptr;
638     NAPI_CALL_BASE(env, napi_get_named_property(env, json, GLOBAL_JSON_PARSE, &parse), undefined);
639     if (GetValueType(env, parse) != napi_function) {
640         return undefined;
641     }
642 
643     napi_value res = nullptr;
644     napi_value argv[1] = {str};
645     NAPI_CALL_BASE(env, napi_call_function(env, json, parse, 1, argv, &res), undefined);
646     return res;
647 }
648 
649 /* libuv */
CreateUvQueueWork(napi_env env,void * data,void (handler)(uv_work_t *,int status))650 void CreateUvQueueWork(napi_env env, void *data, void(handler)(uv_work_t *, int status))
651 {
652     uv_loop_s *loop = nullptr;
653     if (!IsEnvValid(env)) {
654         NETSTACK_LOGE("the env is invalid");
655         return;
656     }
657     napi_get_uv_event_loop(env, &loop);
658     if (!loop) {
659         NETSTACK_LOGE("napi get uv event loop is null");
660         return;
661     }
662 
663     auto work = new uv_work_t;
664     work->data = data;
665 
666     int ret = uv_queue_work_with_qos(
667         loop, work, [](uv_work_t *) {}, handler, uv_qos_default);
668     if (ret != 0) {
669         NETSTACK_LOGE("uv_queue_work_with_qos error = %{public}d, manual delete", ret);
670         delete static_cast<UvWorkWrapperShared *>(work->data);
671         delete work;
672     }
673 }
674 
675 /* scope */
OpenScope(napi_env env)676 napi_handle_scope OpenScope(napi_env env)
677 {
678     napi_handle_scope scope = nullptr;
679     NAPI_CALL(env, napi_open_handle_scope(env, &scope));
680     return scope;
681 }
682 
CloseScope(napi_env env,napi_handle_scope scope)683 void CloseScope(napi_env env, napi_handle_scope scope)
684 {
685     (void)napi_close_handle_scope(env, scope);
686 }
687 
UvQueueWorkCallback(uv_work_t * work,int status)688 static void UvQueueWorkCallback(uv_work_t *work, int status)
689 {
690     auto workData = static_cast<WorkData *>(work->data);
691     if (!workData) {
692         delete work;
693         return;
694     }
695 
696     if (!workData->env_ || !workData->data_ || !workData->handler_) {
697         delete workData;
698         delete work;
699         return;
700     }
701 
702     napi_env env = workData->env_;
703     auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
704     std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
705 
706     workData->handler_(workData->env_, static_cast<napi_status>(status), workData->data_);
707 
708     delete workData;
709     delete work;
710 };
711 
CreateUvQueueWorkEnhanced(napi_env env,void * data,void (* handler)(napi_env env,napi_status status,void * data))712 void CreateUvQueueWorkEnhanced(napi_env env, void *data, void (*handler)(napi_env env, napi_status status, void *data))
713 {
714     uv_loop_s *loop = nullptr;
715     if (!IsEnvValid(env)) {
716         NETSTACK_LOGE("the env is invalid");
717         return;
718     }
719     napi_get_uv_event_loop(env, &loop);
720 
721     if (loop == nullptr) {
722         NETSTACK_LOGE("napi get uv event loop is nullptr");
723         return;
724     }
725 
726     auto workData = new WorkData(env, data, handler);
727 
728     auto work = new (std::nothrow) uv_work_t;
729     if (work == nullptr) {
730         delete workData;
731         return;
732     }
733     work->data = reinterpret_cast<void *>(workData);
734 
735     int ret = uv_queue_work_with_qos(
736         loop, work, [](uv_work_t *) {}, UvQueueWorkCallback, uv_qos_default);
737     if (ret != 0) {
738         NETSTACK_LOGE("uv_queue_work_with_qos error = %{public}d, manual release", ret);
739         delete static_cast<WorkData *>(work->data);
740         delete work;
741     }
742 }
743 
744 /* error */
CreateErrorMessage(napi_env env,int32_t errorCode,const std::string & errorMessage)745 napi_value CreateErrorMessage(napi_env env, int32_t errorCode, const std::string &errorMessage)
746 {
747     napi_value result = nullptr;
748     result = CreateObject(env);
749     SetNamedProperty(env, result, CODE, CreateInt32(env, errorCode));
750     SetNamedProperty(env, result, MSG, CreateStringUtf8(env, errorMessage));
751     return result;
752 }
753 
GetGlobal(napi_env env)754 napi_value GetGlobal(napi_env env)
755 {
756     napi_value undefined = GetUndefined(env);
757     napi_value global = nullptr;
758     NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
759     return global;
760 }
761 
CreateUvHandlerQueue(napi_env env)762 uint64_t CreateUvHandlerQueue(napi_env env)
763 {
764     static std::atomic<uint64_t> id = 1; // start from 1
765     uint64_t newId = id++;
766     NETSTACK_LOGI("newId = %{public}s, id = %{public}s", std::to_string(newId).c_str(), std::to_string(id).c_str());
767 
768     auto global = GetGlobal(env);
769     auto queueWrapper = CreateObject(env);
770     SetNamedProperty(env, global, HTTP_UV_SYNC_QUEUE_NAME, queueWrapper);
771     {
772         std::lock_guard lock(g_mutex);
773         g_handlerQueueMap.emplace(newId, std::make_shared<UvHandlerQueue>());
774     }
775     napi_wrap(
776         env, queueWrapper, reinterpret_cast<void *>(newId),
777         [](napi_env env, void *data, void *) {
778             auto id = reinterpret_cast<uint64_t>(data);
779             std::lock_guard lock(g_mutex);
780             g_handlerQueueMap.erase(id);
781         },
782         nullptr, nullptr);
783     auto envWrapper = new (std::nothrow) napi_env;
784     if (envWrapper == nullptr) {
785         return newId;
786     }
787     *envWrapper = env;
788     napi_add_env_cleanup_hook(
789         env,
790         [](void *data) {
791             auto envWrapper = reinterpret_cast<napi_env *>(data);
792             if (envWrapper == nullptr) {
793                 return;
794             }
795             auto env = *envWrapper;
796             delete envWrapper;
797             if (env == nullptr) {
798                 return;
799             }
800             auto queueWrapper = NapiUtils::GetValueFromGlobal(env, HTTP_UV_SYNC_QUEUE_NAME);
801             if (queueWrapper == nullptr) {
802                 return;
803             }
804             void *result = nullptr;
805             napi_remove_wrap(env, queueWrapper, &result);
806         },
807         envWrapper);
808     return newId;
809 }
810 
GetValueFromGlobal(napi_env env,const std::string & className)811 napi_value GetValueFromGlobal(napi_env env, const std::string &className)
812 {
813     auto global = NapiUtils::GetGlobal(env);
814     if (NapiUtils::GetValueType(env, global) == napi_undefined) {
815         return GetUndefined(env);
816     }
817     return NapiUtils::GetNamedProperty(env, global, className);
818 }
819 
MakeUvCallback()820 static uv_after_work_cb MakeUvCallback()
821 {
822     return [](uv_work_t *work, int status) {
823         if (!work) {
824             return;
825         }
826         std::unique_ptr<uv_work_t> workHandle(work);
827 
828         if (!work->data) {
829             return;
830         }
831         auto env = reinterpret_cast<napi_env>(work->data);
832         if (!env) {
833             return;
834         }
835 
836         auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
837         std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
838         auto queueWrapper = NapiUtils::GetValueFromGlobal(env, HTTP_UV_SYNC_QUEUE_NAME);
839         if (!queueWrapper) {
840             return;
841         }
842         void *theId = nullptr;
843         napi_unwrap(env, queueWrapper, &theId);
844         if (!theId) { // that is why moduleId is started from 1
845             return;
846         }
847         UvHandler handler;
848         {
849             std::lock_guard lock(g_mutex);
850             auto it = g_handlerQueueMap.find(reinterpret_cast<uint64_t>(theId));
851             if (it == g_handlerQueueMap.end()) {
852                 return;
853             }
854             handler = it->second->Pop();
855         }
856         if (handler) {
857             handler();
858         }
859     };
860 }
861 
CreateUvQueueWorkByModuleId(napi_env env,const UvHandler & handler,uint64_t id)862 void CreateUvQueueWorkByModuleId(napi_env env, const UvHandler &handler, uint64_t id)
863 {
864     uv_loop_s *loop = nullptr;
865     if (!IsEnvValid(env)) {
866         NETSTACK_LOGE("the env is invalid");
867         return;
868     }
869     napi_get_uv_event_loop(env, &loop);
870     if (!loop) {
871         return;
872     }
873     uv_work_t *work = nullptr;
874     {
875         std::lock_guard lock(g_mutex);
876         auto it = g_handlerQueueMap.find(id);
877         if (it == g_handlerQueueMap.end()) {
878             return;
879         }
880         work = new (std::nothrow) uv_work_t;
881         if (work == nullptr) {
882             return;
883         }
884         work->data = env;
885         it->second->Push(handler);
886     }
887 
888     if (work) {
889         int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t *) {}, MakeUvCallback(), uv_qos_default);
890         if (ret != 0) {
891             NETSTACK_LOGE("uv_queue_work_with_qos MakeUvCallback error = %{public}d, manual delete", ret);
892             delete static_cast<UvWorkWrapperShared *>(work->data);
893             delete work;
894         }
895     }
896 }
897 
Pop()898 UvHandler UvHandlerQueue::Pop()
899 {
900     std::lock_guard lock(mutex);
901     if (empty()) {
902         return {};
903     }
904     auto s = front();
905     pop();
906     return s;
907 }
908 
Push(const UvHandler & handler)909 void UvHandlerQueue::Push(const UvHandler &handler)
910 {
911     std::lock_guard lock(mutex);
912     push(handler);
913 }
914 
HookForEnvCleanup(void * data)915 void HookForEnvCleanup(void *data)
916 {
917     std::lock_guard<std::mutex> lock(mutexForEnv);
918     auto envWrapper = reinterpret_cast<napi_env*>(data);
919     if (envWrapper == nullptr) {
920         return;
921     }
922     auto env = *envWrapper;
923     delete envWrapper;
924     if (env == nullptr) {
925         return;
926     }
927     auto pos = unorderedSetEnv.find(env);
928     if (pos == unorderedSetEnv.end()) {
929         NETSTACK_LOGE("The env is not in the unordered set");
930         return;
931     }
932     NETSTACK_LOGD("env clean up, erase from the unordered set");
933     unorderedSetEnv.erase(pos);
934 }
935 
SetEnvValid(napi_env env)936 void SetEnvValid(napi_env env)
937 {
938     std::lock_guard<std::mutex> lock(mutexForEnv);
939     unorderedSetEnv.emplace(env);
940 }
941 
IsEnvValid(napi_env env)942 bool IsEnvValid(napi_env env)
943 {
944     std::lock_guard<std::mutex> lock(mutexForEnv);
945     auto pos = unorderedSetEnv.find(env);
946     if (pos == unorderedSetEnv.end()) {
947         return false;
948     }
949     return true;
950 }
951 } // namespace OHOS::NetStack::NapiUtils
952