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