1 /*
2 * Copyright (c) 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 #include "napi_util.h"
16
17 #include <unordered_map>
18
19 #include "hiappevent_base.h"
20 #include "hilog/log.h"
21
22 namespace OHOS {
23 namespace HiviewDFX {
24 namespace NapiUtil {
25 namespace {
26 constexpr HiLogLabel LABEL = { LOG_CORE, HIAPPEVENT_DOMAIN, "HiAppEvent_NapiUtil" };
27 const std::string DOMAIN_PROPERTY = "domain";
28 const std::string NAME_PROPERTY = "name";
29 const std::string EVENT_TYPE_PROPERTY = "eventType";
30 const std::string PARAM_PROPERTY = "params";
31 const std::string EVENT_INFOS_PROPERTY = "appEventInfos";
32 }
33
IsNull(const napi_env env,const napi_value value)34 bool IsNull(const napi_env env, const napi_value value)
35 {
36 return GetType(env, value) == napi_null;
37 }
38
IsBoolean(const napi_env env,const napi_value value)39 bool IsBoolean(const napi_env env, const napi_value value)
40 {
41 return GetType(env, value) == napi_boolean;
42 }
43
IsNumber(const napi_env env,const napi_value value)44 bool IsNumber(const napi_env env, const napi_value value)
45 {
46 return GetType(env, value) == napi_number;
47 }
48
IsString(const napi_env env,const napi_value value)49 bool IsString(const napi_env env, const napi_value value)
50 {
51 return GetType(env, value) == napi_string;
52 }
53
IsObject(const napi_env env,const napi_value value)54 bool IsObject(const napi_env env, const napi_value value)
55 {
56 return GetType(env, value) == napi_object;
57 }
58
IsFunction(const napi_env env,const napi_value value)59 bool IsFunction(const napi_env env, const napi_value value)
60 {
61 return GetType(env, value) == napi_function;
62 }
63
IsArray(const napi_env env,const napi_value value)64 bool IsArray(const napi_env env, const napi_value value)
65 {
66 bool result = false;
67 if (napi_is_array(env, value, &result) != napi_ok) {
68 HiLog::Error(LABEL, "failed to check array type");
69 return false;
70 }
71 return result;
72 }
73
IsArrayType(const napi_env env,const napi_value value,napi_valuetype type)74 bool IsArrayType(const napi_env env, const napi_value value, napi_valuetype type)
75 {
76 if (!IsArray(env, value)) {
77 return false;
78 }
79 if (GetArrayLength(env, value) == 0) {
80 return true;
81 }
82 return GetArrayType(env, value) == type;
83 }
84
GetType(const napi_env env,const napi_value value)85 napi_valuetype GetType(const napi_env env, const napi_value value)
86 {
87 napi_valuetype type;
88 if (napi_typeof(env, value, &type) != napi_ok) {
89 HiLog::Error(LABEL, "failed to get value type");
90 return napi_undefined;
91 }
92 return type;
93 }
94
GetArrayType(const napi_env env,const napi_value arr)95 napi_valuetype GetArrayType(const napi_env env, const napi_value arr)
96 {
97 uint32_t result = 0;
98 if (napi_get_array_length(env, arr, &result) != napi_ok) {
99 HiLog::Error(LABEL, "failed to get the length of array");
100 return napi_undefined;
101 }
102
103 napi_valuetype type = napi_null; // note: empty array returns null type
104 for (size_t i = 0; i < result; ++i) {
105 napi_value element = nullptr;
106 if (napi_get_element(env, arr, i, &element) != napi_ok) {
107 HiLog::Error(LABEL, "failed to get the element of array");
108 return napi_undefined;
109 }
110 if (i == 0) {
111 type = GetType(env, element);
112 continue;
113 }
114 if (type != GetType(env, element)) {
115 HiLog::Error(LABEL, "array has different element types");
116 return napi_undefined;
117 }
118 }
119 return type;
120 }
121
GetArrayLength(const napi_env env,const napi_value arr)122 uint32_t GetArrayLength(const napi_env env, const napi_value arr)
123 {
124 uint32_t result = 0;
125 if (napi_get_array_length(env, arr, &result) != napi_ok) {
126 HiLog::Error(LABEL, "failed to get the length of array");
127 return 0;
128 }
129 return result;
130 }
131
GetElement(const napi_env env,const napi_value arr,uint32_t index)132 napi_value GetElement(const napi_env env, const napi_value arr, uint32_t index)
133 {
134 napi_value element = nullptr;
135 if (napi_get_element(env, arr, index, &element) != napi_ok) {
136 HiLog::Error(LABEL, "failed to get the element of array.");
137 return nullptr;
138 }
139 return element;
140 }
141
GetBoolean(const napi_env env,const napi_value value)142 bool GetBoolean(const napi_env env, const napi_value value)
143 {
144 bool bValue = false;
145 if (napi_get_value_bool(env, value, &bValue) != napi_ok) {
146 HiLog::Error(LABEL, "failed to get bool value");
147 return false;
148 }
149 return bValue;
150 }
151
GetBooleans(const napi_env env,const napi_value arr,std::vector<bool> & bools)152 void GetBooleans(const napi_env env, const napi_value arr, std::vector<bool>& bools)
153 {
154 uint32_t len = GetArrayLength(env, arr);
155 for (size_t i = 0; i < len; ++i) {
156 napi_value element = GetElement(env, arr, i);
157 if (element == nullptr) {
158 continue;
159 }
160 bools.push_back(GetBoolean(env, element));
161 }
162 }
163
GetInt32(const napi_env env,const napi_value value)164 int32_t GetInt32(const napi_env env, const napi_value value)
165 {
166 int32_t iValue = 0;
167 if (napi_get_value_int32(env, value, &iValue) != napi_ok) {
168 HiLog::Error(LABEL, "failed to get int32 value");
169 return 0;
170 }
171 return iValue;
172 }
173
GetInt64(const napi_env env,const napi_value value)174 int64_t GetInt64(const napi_env env, const napi_value value)
175 {
176 int64_t iValue = 0;
177 if (napi_get_value_int64(env, value, &iValue) != napi_ok) {
178 HiLog::Error(LABEL, "failed to get int64 value");
179 return 0;
180 }
181 return iValue;
182 }
183
GetInt32s(const napi_env env,const napi_value arr,std::vector<int32_t> & ints)184 void GetInt32s(const napi_env env, const napi_value arr, std::vector<int32_t>& ints)
185 {
186 uint32_t len = GetArrayLength(env, arr);
187 for (size_t i = 0; i < len; ++i) {
188 napi_value element = GetElement(env, arr, i);
189 if (element == nullptr) {
190 continue;
191 }
192 ints.push_back(GetInt32(env, element));
193 }
194 }
195
GetDouble(const napi_env env,const napi_value value)196 double GetDouble(const napi_env env, const napi_value value)
197 {
198 double dValue = 0;
199 if (napi_get_value_double(env, value, &dValue) != napi_ok) {
200 HiLog::Error(LABEL, "failed to get double value");
201 return 0;
202 }
203 return dValue;
204 }
205
GetDoubles(const napi_env env,const napi_value arr,std::vector<double> & doubles)206 void GetDoubles(const napi_env env, const napi_value arr, std::vector<double>& doubles)
207 {
208 uint32_t len = GetArrayLength(env, arr);
209 for (size_t i = 0; i < len; ++i) {
210 napi_value element = GetElement(env, arr, i);
211 if (element == nullptr) {
212 continue;
213 }
214 doubles.push_back(GetDouble(env, element));
215 }
216 }
217
GetString(const napi_env env,const napi_value value)218 std::string GetString(const napi_env env, const napi_value value)
219 {
220 size_t bufsize = 0;
221 if (napi_get_value_string_utf8(env, value, nullptr, 0, &bufsize) != napi_ok) {
222 HiLog::Error(LABEL, "failed to get string length");
223 return "";
224 }
225 std::vector<char> charVec(bufsize + 1); // 1 for '\0'
226 if (napi_get_value_string_utf8(env, value, charVec.data(), bufsize + 1, &bufsize) != napi_ok) {
227 HiLog::Error(LABEL, "failed to get string value");
228 return "";
229 }
230 return charVec.data();
231 }
232
GetStrings(const napi_env env,const napi_value arr,std::vector<std::string> & strs)233 void GetStrings(const napi_env env, const napi_value arr, std::vector<std::string>& strs)
234 {
235 uint32_t len = GetArrayLength(env, arr);
236 for (size_t i = 0; i < len; ++i) {
237 napi_value element = GetElement(env, arr, i);
238 if (element == nullptr) {
239 continue;
240 }
241 strs.push_back(GetString(env, element));
242 }
243 }
244
GetStringsToSet(const napi_env env,const napi_value arr,std::unordered_set<std::string> & strs)245 void GetStringsToSet(const napi_env env, const napi_value arr, std::unordered_set<std::string>& strs)
246 {
247 uint32_t len = GetArrayLength(env, arr);
248 for (size_t i = 0; i < len; ++i) {
249 napi_value element = GetElement(env, arr, i);
250 if (element == nullptr) {
251 continue;
252 }
253 strs.insert(GetString(env, element));
254 }
255 }
256
HasProperty(const napi_env env,const napi_value object,const std::string & name)257 bool HasProperty(const napi_env env, const napi_value object, const std::string& name)
258 {
259 bool result = false;
260 if (napi_has_named_property(env, object, name.c_str(), &result) != napi_ok) {
261 HiLog::Error(LABEL, "failed to check whether the object has the named property");
262 return false;
263 }
264 return result;
265 }
266
GetProperty(const napi_env env,const napi_value object,const std::string & name)267 napi_value GetProperty(const napi_env env, const napi_value object, const std::string& name)
268 {
269 if (!HasProperty(env, object, name)) {
270 return nullptr;
271 }
272 napi_value value = nullptr;
273 if (napi_get_named_property(env, object, name.c_str(), &value) != napi_ok) {
274 HiLog::Error(LABEL, "failed to get property=%{public}s from object", name.c_str());
275 return nullptr;
276 }
277 return value;
278 }
279
GetPropertyNames(const napi_env env,const napi_value object,std::vector<std::string> & names)280 void GetPropertyNames(const napi_env env, const napi_value object, std::vector<std::string>& names)
281 {
282 napi_value propertyNames = nullptr;
283 if (napi_get_property_names(env, object, &propertyNames) != napi_ok) {
284 HiLog::Error(LABEL, "failed to get property names.");
285 return;
286 }
287 uint32_t len = 0;
288 if (napi_get_array_length(env, propertyNames, &len) != napi_ok) {
289 HiLog::Error(LABEL, "failed to get array length");
290 return;
291 }
292 for (uint32_t i = 0; i < len; ++i) {
293 napi_value element = nullptr;
294 if (napi_get_element(env, propertyNames, i, &element) != napi_ok) {
295 HiLog::Error(LABEL, "failed to get the element of array");
296 continue;
297 }
298 names.push_back(GetString(env, element));
299 }
300 }
301
GetReferenceValue(const napi_env env,const napi_ref funcRef)302 napi_value GetReferenceValue(const napi_env env, const napi_ref funcRef)
303 {
304 napi_value refValue = nullptr;
305 if (napi_get_reference_value(env, funcRef, &refValue) != napi_ok) {
306 HiLog::Error(LABEL, "failed to get reference value");
307 return nullptr;
308 }
309 return refValue;
310 }
311
GetCbInfo(const napi_env env,napi_callback_info info,napi_value argv[],size_t argc)312 size_t GetCbInfo(const napi_env env, napi_callback_info info, napi_value argv[], size_t argc)
313 {
314 size_t paramNum = argc;
315 if (napi_get_cb_info(env, info, ¶mNum, argv, nullptr, nullptr) != napi_ok) {
316 HiLog::Error(LABEL, "failed to get callback info");
317 return 0;
318 }
319 return paramNum;
320 }
321
CreateReference(const napi_env env,const napi_value func)322 napi_ref CreateReference(const napi_env env, const napi_value func)
323 {
324 napi_ref ref = nullptr;
325 if (napi_create_reference(env, func, 1, &ref) != napi_ok) { // 1 means initial reference count
326 HiLog::Error(LABEL, "failed to create reference");
327 return nullptr;
328 }
329 return ref;
330 }
331
CreateNull(const napi_env env)332 napi_value CreateNull(const napi_env env)
333 {
334 napi_value nullValue = nullptr;
335 if (napi_get_null(env, &nullValue) != napi_ok) {
336 HiLog::Error(LABEL, "failed to create null");
337 return nullptr;
338 }
339 return nullValue;
340 }
341
CreateUndefined(const napi_env env)342 napi_value CreateUndefined(const napi_env env)
343 {
344 napi_value undefinedValue = nullptr;
345 if (napi_get_undefined(env, &undefinedValue) != napi_ok) {
346 HiLog::Error(LABEL, "failed to create undefined");
347 return nullptr;
348 }
349 return undefinedValue;
350 }
351
CreateBoolean(const napi_env env,bool bValue)352 napi_value CreateBoolean(const napi_env env, bool bValue)
353 {
354 napi_value boolValue = nullptr;
355 if (napi_get_boolean(env, bValue, &boolValue) != napi_ok) {
356 HiLog::Error(LABEL, "failed to create boolean");
357 return nullptr;
358 }
359 return boolValue;
360 }
361
CreateInt32(const napi_env env,int32_t num)362 napi_value CreateInt32(const napi_env env, int32_t num)
363 {
364 napi_value intValue = nullptr;
365 if (napi_create_int32(env, num, &intValue) != napi_ok) {
366 HiLog::Error(LABEL, "failed to create int32");
367 return nullptr;
368 }
369 return intValue;
370 }
371
CreateInt64(const napi_env env,int64_t num)372 napi_value CreateInt64(const napi_env env, int64_t num)
373 {
374 napi_value intValue = nullptr;
375 if (napi_create_int64(env, num, &intValue) != napi_ok) {
376 HiLog::Error(LABEL, "failed to create int64");
377 return nullptr;
378 }
379 return intValue;
380 }
381
CreateString(const napi_env env,const std::string & str)382 napi_value CreateString(const napi_env env, const std::string& str)
383 {
384 napi_value strValue = nullptr;
385 if (napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &strValue) != napi_ok) {
386 HiLog::Error(LABEL, "failed to create string");
387 return nullptr;
388 }
389 return strValue;
390 }
391
CreateStrings(const napi_env env,const std::vector<std::string> & strs)392 napi_value CreateStrings(const napi_env env, const std::vector<std::string>& strs)
393 {
394 napi_value arr = CreateArray(env);
395 for (size_t i = 0; i < strs.size(); ++i) {
396 SetElement(env, arr, i, CreateString(env, strs[i]));
397 }
398 return arr;
399 }
400
CreateObject(const napi_env env)401 napi_value CreateObject(const napi_env env)
402 {
403 napi_value obj = nullptr;
404 if (napi_create_object(env, &obj) != napi_ok) {
405 HiLog::Error(LABEL, "failed to create object");
406 return nullptr;
407 }
408 return obj;
409 }
410
CreateObject(const napi_env env,const std::string & key,const napi_value value)411 napi_value CreateObject(const napi_env env, const std::string& key, const napi_value value)
412 {
413 napi_value obj = nullptr;
414 if (napi_create_object(env, &obj) != napi_ok) {
415 HiLog::Error(LABEL, "failed to create object");
416 return nullptr;
417 }
418 if (napi_set_named_property(env, obj, key.c_str(), value) != napi_ok) {
419 HiLog::Error(LABEL, "failed to set property");
420 return nullptr;
421 }
422 return obj;
423 }
424
CreateArray(const napi_env env)425 napi_value CreateArray(const napi_env env)
426 {
427 napi_value arr = nullptr;
428 if (napi_create_array(env, &arr) != napi_ok) {
429 HiLog::Error(LABEL, "failed to create array");
430 return nullptr;
431 }
432 return arr;
433 }
434
CreateDouble(const napi_env env,double dValue)435 napi_value CreateDouble(const napi_env env, double dValue)
436 {
437 napi_value doubleValue = nullptr;
438 if (napi_create_double(env, dValue, &doubleValue) != napi_ok) {
439 HiLog::Error(LABEL, "failed to create double");
440 return nullptr;
441 }
442 return doubleValue;
443 }
444
SetElement(const napi_env env,const napi_value obj,uint32_t index,const napi_value value)445 void SetElement(const napi_env env, const napi_value obj, uint32_t index, const napi_value value)
446 {
447 if (napi_set_element(env, obj, index, value) != napi_ok) {
448 HiLog::Error(LABEL, "failed to set element");
449 }
450 }
451
SetNamedProperty(const napi_env env,const napi_value obj,const std::string & key,const napi_value value)452 void SetNamedProperty(const napi_env env, const napi_value obj, const std::string& key, const napi_value value)
453 {
454 if (napi_set_named_property(env, obj, key.c_str(), value) != napi_ok) {
455 HiLog::Error(LABEL, "failed to set property");
456 }
457 }
458
ConvertToString(const napi_env env,const napi_value value)459 std::string ConvertToString(const napi_env env, const napi_value value)
460 {
461 napi_valuetype type = GetType(env, value);
462 if (type == napi_undefined) {
463 return "";
464 }
465
466 std::string result = "";
467 switch (type) {
468 case napi_boolean:
469 result = GetBoolean(env, value) ? "true" : "false";
470 break;
471 case napi_number:
472 result = std::to_string(GetDouble(env, value));
473 break;
474 case napi_string:
475 result = GetString(env, value);
476 break;
477 default:
478 break;
479 }
480 return result;
481 }
482
ThrowError(napi_env env,int code,const std::string & msg,bool isThrow)483 void ThrowError(napi_env env, int code, const std::string& msg, bool isThrow)
484 {
485 // no error needs to be thrown before api 9
486 if (!isThrow) {
487 return;
488 }
489
490 if (napi_throw_error(env, std::to_string(code).c_str(), msg.c_str()) != napi_ok) {
491 HiLog::Error(LABEL, "failed to throw error, code=%{public}d, msg=%{public}s", code, msg.c_str());
492 }
493 }
494
CreateError(napi_env env,int code,const std::string & msg)495 napi_value CreateError(napi_env env, int code, const std::string& msg)
496 {
497 napi_value err = nullptr;
498 if (napi_create_error(env, CreateString(env, std::to_string(code)), CreateString(env, msg), &err) != napi_ok) {
499 HiLog::Error(LABEL, "failed to create error");
500 return nullptr;
501 }
502 return err;
503 }
504
CreateErrMsg(const std::string & name)505 std::string CreateErrMsg(const std::string& name)
506 {
507 return "Parameter error. The " + name + " parameter is mandatory.";
508 }
509
CreateErrMsg(const std::string & name,const std::string & type)510 std::string CreateErrMsg(const std::string& name, const std::string& type)
511 {
512 return "Parameter error. The type of " + name + " must be " + type + ".";
513 }
CreateErrMsg(const std::string & name,const napi_valuetype type)514 std::string CreateErrMsg(const std::string& name, const napi_valuetype type)
515 {
516 std::string typeStr = "";
517 switch (type) {
518 case napi_boolean:
519 typeStr = "boolean";
520 break;
521 case napi_number:
522 typeStr = "number";
523 break;
524 case napi_string:
525 typeStr = "string";
526 break;
527 case napi_object:
528 typeStr = "object";
529 break;
530 default:
531 break;
532 }
533 return CreateErrMsg(name, typeStr);
534 }
535
CreateBaseValueByJson(const napi_env env,const Json::Value & jsonValue)536 napi_value CreateBaseValueByJson(const napi_env env, const Json::Value& jsonValue)
537 {
538 if (jsonValue.isBool()) {
539 return CreateBoolean(env, jsonValue.asBool());
540 }
541 if (jsonValue.isInt()) {
542 return CreateInt32(env, jsonValue.asInt());
543 }
544 if (jsonValue.isInt64() && jsonValue.type() != Json::ValueType::uintValue) {
545 return CreateInt64(env, jsonValue.asInt64());
546 }
547 if (jsonValue.isDouble()) {
548 return CreateDouble(env, jsonValue.asDouble());
549 }
550 if (jsonValue.isString()) {
551 return CreateString(env, jsonValue.asString());
552 }
553 return nullptr;
554 }
555
CreateValueByJson(napi_env env,const Json::Value & jsonValue)556 napi_value CreateValueByJson(napi_env env, const Json::Value& jsonValue)
557 {
558 if (jsonValue.isArray()) {
559 napi_value array = CreateArray(env);
560 for (size_t i = 0; i < jsonValue.size(); ++i) {
561 SetElement(env, array, i, CreateValueByJson(env, jsonValue[static_cast<int>(i)]));
562 }
563 return array;
564 }
565 if (jsonValue.isObject()) {
566 napi_value obj = CreateObject(env);
567 auto eventNameList = jsonValue.getMemberNames();
568 for (auto it = eventNameList.cbegin(); it != eventNameList.cend(); ++it) {
569 auto propertyName = *it;
570 SetNamedProperty(env, obj, propertyName, CreateValueByJson(env, jsonValue[propertyName]));
571 }
572 return obj;
573 }
574 return CreateBaseValueByJson(env, jsonValue);
575 }
576
CreateValueByJsonStr(napi_env env,const std::string & jsonStr)577 napi_value CreateValueByJsonStr(napi_env env, const std::string& jsonStr)
578 {
579 Json::Value jsonValue;
580 Json::Reader reader(Json::Features::strictMode());
581 if (!reader.parse(jsonStr, jsonValue)) {
582 HiLog::Error(LABEL, "parse event detail info failed, please check the style of json");
583 return nullptr;
584 }
585 return CreateValueByJson(env, jsonValue);
586 }
587
CreateEventInfo(napi_env env,std::shared_ptr<AppEventPack> event)588 napi_value CreateEventInfo(napi_env env, std::shared_ptr<AppEventPack> event)
589 {
590 napi_value obj = CreateObject(env);
591 SetNamedProperty(env, obj, DOMAIN_PROPERTY, CreateString(env, event->GetDomain()));
592 SetNamedProperty(env, obj, NAME_PROPERTY, CreateString(env, event->GetName()));
593 SetNamedProperty(env, obj, EVENT_TYPE_PROPERTY, CreateInt32(env, event->GetType()));
594 SetNamedProperty(env, obj, PARAM_PROPERTY, CreateValueByJsonStr(env, event->GetParamStr()));
595 return obj;
596 }
597
CreateEventGroups(napi_env env,const std::vector<std::shared_ptr<AppEventPack>> & events)598 napi_value CreateEventGroups(napi_env env, const std::vector<std::shared_ptr<AppEventPack>>& events)
599 {
600 std::unordered_map<std::string, std::vector<std::shared_ptr<AppEventPack>>> eventMap;
601 for (auto event : events) {
602 eventMap[event->GetName()].emplace_back(event);
603 }
604
605 napi_value eventGroups = CreateArray(env);
606 size_t index = 0;
607 for (auto it = eventMap.begin(); it != eventMap.end(); ++it) {
608 napi_value eventInfos = CreateArray(env);
609 for (size_t i = 0; i < it->second.size(); ++i) {
610 SetElement(env, eventInfos, i, CreateEventInfo(env, it->second[i]));
611 }
612 napi_value obj = CreateObject(env);
613 SetNamedProperty(env, obj, NAME_PROPERTY, CreateString(env, it->first));
614 SetNamedProperty(env, obj, EVENT_INFOS_PROPERTY, eventInfos);
615 SetElement(env, eventGroups, index, obj);
616 ++index;
617 }
618 return eventGroups;
619 }
620 } // namespace NapiUtil
621 } // namespace HiviewDFX
622 } // namespace OHOS
623