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