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 auto id = reinterpret_cast<uint64_t>(result);
807 std::lock_guard lock(g_mutex);
808 g_handlerQueueMap.erase(id);
809 },
810 envWrapper);
811 return newId;
812 }
813
GetValueFromGlobal(napi_env env,const std::string & className)814 napi_value GetValueFromGlobal(napi_env env, const std::string &className)
815 {
816 auto global = NapiUtils::GetGlobal(env);
817 if (NapiUtils::GetValueType(env, global) == napi_undefined) {
818 return GetUndefined(env);
819 }
820 return NapiUtils::GetNamedProperty(env, global, className);
821 }
822
MakeUvCallback()823 static uv_after_work_cb MakeUvCallback()
824 {
825 return [](uv_work_t *work, int status) {
826 if (!work) {
827 return;
828 }
829 std::unique_ptr<uv_work_t> workHandle(work);
830
831 if (!work->data) {
832 return;
833 }
834 auto env = reinterpret_cast<napi_env>(work->data);
835 if (!env) {
836 return;
837 }
838
839 auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
840 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
841 auto queueWrapper = NapiUtils::GetValueFromGlobal(env, HTTP_UV_SYNC_QUEUE_NAME);
842 if (!queueWrapper) {
843 return;
844 }
845 void *theId = nullptr;
846 napi_unwrap(env, queueWrapper, &theId);
847 if (!theId) { // that is why moduleId is started from 1
848 return;
849 }
850 UvHandler handler;
851 {
852 std::lock_guard lock(g_mutex);
853 auto it = g_handlerQueueMap.find(reinterpret_cast<uint64_t>(theId));
854 if (it == g_handlerQueueMap.end()) {
855 return;
856 }
857 handler = it->second->Pop();
858 }
859 if (handler) {
860 handler();
861 }
862 };
863 }
864
CreateUvQueueWorkByModuleId(napi_env env,const UvHandler & handler,uint64_t id)865 void CreateUvQueueWorkByModuleId(napi_env env, const UvHandler &handler, uint64_t id)
866 {
867 uv_loop_s *loop = nullptr;
868 if (!IsEnvValid(env)) {
869 NETSTACK_LOGE("the env is invalid");
870 return;
871 }
872 napi_get_uv_event_loop(env, &loop);
873 if (!loop) {
874 return;
875 }
876 uv_work_t *work = nullptr;
877 {
878 std::lock_guard lock(g_mutex);
879 auto it = g_handlerQueueMap.find(id);
880 if (it == g_handlerQueueMap.end()) {
881 return;
882 }
883 work = new (std::nothrow) uv_work_t;
884 if (work == nullptr) {
885 return;
886 }
887 work->data = env;
888 it->second->Push(handler);
889 }
890
891 if (work) {
892 int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t *) {}, MakeUvCallback(), uv_qos_default);
893 if (ret != 0) {
894 NETSTACK_LOGE("uv_queue_work_with_qos MakeUvCallback error = %{public}d, manual delete", ret);
895 delete static_cast<UvWorkWrapperShared *>(work->data);
896 delete work;
897 }
898 }
899 }
900
Pop()901 UvHandler UvHandlerQueue::Pop()
902 {
903 std::lock_guard lock(mutex);
904 if (empty()) {
905 return {};
906 }
907 auto s = front();
908 pop();
909 return s;
910 }
911
Push(const UvHandler & handler)912 void UvHandlerQueue::Push(const UvHandler &handler)
913 {
914 std::lock_guard lock(mutex);
915 push(handler);
916 }
917
HookForEnvCleanup(void * data)918 void HookForEnvCleanup(void *data)
919 {
920 std::lock_guard<std::mutex> lock(mutexForEnv);
921 auto envWrapper = reinterpret_cast<napi_env*>(data);
922 if (envWrapper == nullptr) {
923 return;
924 }
925 auto env = *envWrapper;
926 delete envWrapper;
927 if (env == nullptr) {
928 return;
929 }
930 auto pos = unorderedSetEnv.find(env);
931 if (pos == unorderedSetEnv.end()) {
932 NETSTACK_LOGE("The env is not in the unordered set");
933 return;
934 }
935 NETSTACK_LOGD("env clean up, erase from the unordered set");
936 unorderedSetEnv.erase(pos);
937 }
938
SetEnvValid(napi_env env)939 void SetEnvValid(napi_env env)
940 {
941 std::lock_guard<std::mutex> lock(mutexForEnv);
942 unorderedSetEnv.emplace(env);
943 }
944
IsEnvValid(napi_env env)945 bool IsEnvValid(napi_env env)
946 {
947 std::lock_guard<std::mutex> lock(mutexForEnv);
948 auto pos = unorderedSetEnv.find(env);
949 if (pos == unorderedSetEnv.end()) {
950 return false;
951 }
952 return true;
953 }
954 } // namespace OHOS::NetStack::NapiUtils
955