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 16 #ifndef JS_CONCURRENT_MODULE_COMMON_HELPER_ERROR_HELPER_H 17 #define JS_CONCURRENT_MODULE_COMMON_HELPER_ERROR_HELPER_H 18 19 #include <ctime> 20 #include <iomanip> 21 #include <iostream> 22 #include <regex> 23 #include <sstream> 24 #include <vector> 25 26 #include "napi/native_api.h" 27 #include "napi/native_node_api.h" 28 #include "napi_helper.h" 29 #include "native_engine/native_engine.h" 30 31 namespace Commonlibrary::Concurrent::Common::Helper { 32 class ErrorHelper { 33 public: 34 ErrorHelper() = default; 35 ~ErrorHelper() = default; 36 37 static napi_value NewError(napi_env env, int32_t errCode, const char* errMessage = nullptr) 38 { 39 std::string errTitle = ""; 40 napi_value concurrentError = nullptr; 41 42 napi_value code = nullptr; 43 napi_create_uint32(env, errCode, &code); 44 45 napi_value name = nullptr; 46 std::string errName = "BusinessError"; 47 if (errCode == ERR_WORKER_INITIALIZATION) { 48 errTitle = "Worker initialization failure, "; 49 } else if (errCode == ERR_WORKER_NOT_RUNNING) { 50 errTitle = "Worker instance is not running, "; 51 } else if (errCode == ERR_WORKER_UNSUPPORTED) { 52 errTitle = "The invoked API is not supported in workers, "; 53 } else if (errCode == ERR_WORKER_SERIALIZATION) { 54 errTitle = "An exception occurred during serialization, "; 55 } else if (errCode == ERR_WORKER_INVALID_FILEPATH) { 56 errTitle = "The worker file path is invalid path, "; 57 } else if (errCode == ERR_NOT_CONCURRENT_FUNCTION) { 58 errTitle = "The function is not mark as concurrent, "; 59 } else if (errCode == ERR_CANCEL_NONEXIST_TASK) { 60 errTitle = "The task does not exist when it is canceled"; 61 } else if (errCode == ERR_CANCEL_NONEXIST_TASK_GROUP) { 62 errTitle = "The task group does not exist when it is canceled"; 63 } else if (errCode == ERR_CANCEL_RUNNING_TASK) { 64 errTitle = "The task is executing when it is canceled"; 65 } 66 napi_create_string_utf8(env, errName.c_str(), NAPI_AUTO_LENGTH, &name); 67 napi_value msg = nullptr; 68 if (errMessage == nullptr) { 69 napi_create_string_utf8(env, errTitle.c_str(), NAPI_AUTO_LENGTH, &msg); 70 } else { 71 napi_create_string_utf8(env, (errTitle + std::string(errMessage)).c_str(), NAPI_AUTO_LENGTH, &msg); 72 } 73 74 napi_create_error(env, nullptr, msg, &concurrentError); 75 napi_set_named_property(env, concurrentError, "code", code); 76 napi_set_named_property(env, concurrentError, "name", name); 77 return concurrentError; 78 } 79 80 static void ThrowError(napi_env env, int32_t errCode, const char* errMessage = nullptr) 81 { 82 napi_value concurrentError = NewError(env, errCode, errMessage); 83 napi_throw(env, concurrentError); 84 } 85 GetCurrentTimeStamp()86 static std::string GetCurrentTimeStamp() 87 { 88 auto now = std::chrono::system_clock::now(); 89 std::time_t currentTimeStamp = std::chrono::system_clock::to_time_t(now); 90 std::tm* timeInfo = std::localtime(¤tTimeStamp); 91 std::stringstream ss; 92 ss << std::put_time(timeInfo, "%Y-%m-%d %X"); 93 return ss.str(); 94 } 95 GetErrorFileInfo(const std::string & input)96 static std::string GetErrorFileInfo(const std::string& input) 97 { 98 std::regex pattern("\\((.*?)\\)"); 99 std::smatch match; 100 if (std::regex_search(input, match, pattern)) { 101 return match[1].str(); 102 } 103 return ""; 104 } 105 SplitErrorFileInfo(const std::string & input,char delimiter,int count)106 static std::vector<std::string> SplitErrorFileInfo(const std::string& input, char delimiter, int count) 107 { 108 std::vector<std::string> result; 109 std::string rawErrorInfo = GetErrorFileInfo(input); 110 if (rawErrorInfo.empty()) { 111 return result; 112 } 113 114 int pos = rawErrorInfo.rfind(delimiter); 115 while (pos != std::string::npos && count > 0) { 116 result.push_back(rawErrorInfo.substr(pos + 1)); 117 rawErrorInfo = rawErrorInfo.substr(0, pos); 118 pos = rawErrorInfo.rfind(delimiter); 119 count--; 120 } 121 result.push_back(rawErrorInfo); 122 std::reverse(result.begin(), result.end()); 123 return result; 124 } 125 TranslateErrorEvent(napi_env env,napi_value error)126 static napi_value TranslateErrorEvent(napi_env env, napi_value error) 127 { 128 napi_value obj = NapiHelper::CreateObject(env); 129 130 // add message 131 napi_value msgValue = nullptr; 132 napi_coerce_to_string(env, error, &msgValue); 133 napi_set_named_property(env, obj, "message", msgValue); 134 135 // add backtrace 136 napi_value stack = NapiHelper::GetNameProperty(env, error, "stack"); 137 napi_set_named_property(env, obj, "backtrace", stack); 138 139 // add timeStamp 140 std::string current = GetCurrentTimeStamp(); 141 napi_value timeStamp = nullptr; 142 napi_create_string_utf8(env, current.c_str(), NAPI_AUTO_LENGTH, &timeStamp); 143 napi_set_named_property(env, obj, "timeStamp", timeStamp); 144 145 std::string rawStack = NapiHelper::GetString(env, stack); 146 std::vector<std::string> result = SplitErrorFileInfo(rawStack, ':', 2); // 2 : the last two : 147 if (result.size() == 3) { // 3 : the rawStack is divided into three parts by last two : 148 // add filename 149 napi_value filenameValue = nullptr; 150 napi_create_string_utf8(env, result[0].c_str(), NAPI_AUTO_LENGTH, &filenameValue); // 0 : filename 151 napi_set_named_property(env, obj, "filename", filenameValue); 152 153 // add lineno 154 napi_value lineno = nullptr; 155 napi_create_string_utf8(env, result[1].c_str(), NAPI_AUTO_LENGTH, &lineno); // 1 : lineno 156 napi_set_named_property(env, obj, "lineno", lineno); 157 158 // add colno 159 napi_value colno = nullptr; 160 napi_create_string_utf8(env, result[2].c_str(), NAPI_AUTO_LENGTH, &colno); // 2 : colno 161 napi_set_named_property(env, obj, "colno", colno); 162 } 163 164 // add type 165 napi_value eventType = nullptr; 166 napi_create_string_utf8(env, "ErrorEvent", NAPI_AUTO_LENGTH, &eventType); 167 napi_set_named_property(env, obj, "type", eventType); 168 169 // add error 170 napi_set_named_property(env, obj, "error", error); 171 172 return obj; 173 } 174 175 static const int32_t TYPE_ERROR = 401; // 401 : the parameter type is incorrect 176 static const int32_t ERR_WORKER_INITIALIZATION = 10200003; // 10200003 : worker initialization failure 177 static const int32_t ERR_WORKER_NOT_RUNNING = 10200004; // 10200004 : worker instance is not running 178 static const int32_t ERR_WORKER_UNSUPPORTED = 10200005; // 10200005 : the invoked API is not supported in worker 179 static const int32_t ERR_WORKER_SERIALIZATION = 10200006; // 10200006 : serialize an uncaught exception failed 180 static const int32_t ERR_WORKER_INVALID_FILEPATH = 10200007; // 10200007 : the worker file path is invalid path 181 static const int32_t ERR_NOT_CONCURRENT_FUNCTION = 10200014; // 10200014 : the function is not mark as concurrent 182 static const int32_t ERR_CANCEL_NONEXIST_TASK = 10200015; // 10200015 : the task does not exist when it is canceled 183 static const int32_t ERR_CANCEL_RUNNING_TASK = 10200016; // 10200016 : the task is executing when it is canceled 184 static const int32_t ERR_CANCEL_NONEXIST_TASK_GROUP = 10200018; // 10200018 : cancel nonexist task group 185 }; 186 } // namespace Commonlibrary::Concurrent::Common::Helper 187 #endif // JS_CONCURRENT_MODULE_COMMON_HELPER_ERROR_HELPER_H