1 /*
2  * Copyright (c) 2021-2024 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_hiappevent_builder.h"
16 
17 #include "hiappevent_base.h"
18 #include "hiappevent_verify.h"
19 #include "hilog/log.h"
20 #include "napi_error.h"
21 #include "napi_util.h"
22 
23 #undef LOG_DOMAIN
24 #define LOG_DOMAIN 0xD002D07
25 
26 #undef LOG_TAG
27 #define LOG_TAG "NapiEventBuilder"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 const std::string DOMAIN_PROPERTY = "domain";
33 const std::string NAME_PROPERTY = "name";
34 const std::string TYPE_PROPERTY = "eventType";
35 const std::string PARAM_PROPERTY = "params";
36 constexpr size_t MAX_LENGTH_OF_PARAM_NAME = 32;
37 const std::string PARAM_VALUE_TYPE = "boolean|number|string|array[boolean|number|string]";
38 }
39 using namespace OHOS::HiviewDFX::ErrorCode;
40 
IsValidEventDomain(const napi_env env,const napi_value domain)41 bool NapiHiAppEventBuilder::IsValidEventDomain(const napi_env env, const napi_value domain)
42 {
43     if (domain == nullptr) {
44         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("domain"), isV9_);
45         return false;
46     }
47     if (!NapiUtil::IsString(env, domain)) {
48         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("domain", "string"), isV9_);
49         return false;
50     }
51     return true;
52 }
53 
IsValidEventName(const napi_env env,const napi_value name)54 bool NapiHiAppEventBuilder::IsValidEventName(const napi_env env, const napi_value name)
55 {
56     if (name == nullptr) {
57         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("name"), isV9_);
58         return false;
59     }
60     if (!NapiUtil::IsString(env, name)) {
61         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("name", "string"), isV9_);
62         return false;
63     }
64     return true;
65 }
66 
IsValidEventType(const napi_env env,const napi_value type)67 bool NapiHiAppEventBuilder::IsValidEventType(const napi_env env, const napi_value type)
68 {
69     if (type == nullptr) {
70         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("eventType"), isV9_);
71         return false;
72     }
73     if (!NapiUtil::IsNumber(env, type) || !OHOS::HiviewDFX::IsValidEventType(NapiUtil::GetInt32(env, type))) {
74         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("eventType", "EventType"), isV9_);
75         return false;
76     }
77     return true;
78 }
79 
IsValidEventParam(const napi_env env,const napi_value param)80 bool NapiHiAppEventBuilder::IsValidEventParam(const napi_env env, const napi_value param)
81 {
82     if (param == nullptr) {
83         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("params"), isV9_);
84         return false;
85     }
86     if (!NapiUtil::IsObject(env, param)) {
87         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("params", "object"), isV9_);
88         return false;
89     }
90     return true;
91 }
92 
IsValidEventInfo(const napi_env env,const napi_value eventInfo)93 bool NapiHiAppEventBuilder::IsValidEventInfo(const napi_env env, const napi_value eventInfo)
94 {
95     if (!NapiUtil::IsObject(env, eventInfo)) {
96         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("info", "AppEventInfo"), isV9_);
97         return false;
98     }
99     return IsValidEventDomain(env, NapiUtil::GetProperty(env, eventInfo, DOMAIN_PROPERTY))
100         && IsValidEventName(env, NapiUtil::GetProperty(env, eventInfo, NAME_PROPERTY))
101         && IsValidEventType(env, NapiUtil::GetProperty(env, eventInfo, TYPE_PROPERTY))
102         && IsValidEventParam(env, NapiUtil::GetProperty(env, eventInfo, PARAM_PROPERTY));
103 }
104 
IsOldWriteParams(const napi_env env,const napi_value params[],size_t len)105 bool NapiHiAppEventBuilder::IsOldWriteParams(const napi_env env, const napi_value params[], size_t len)
106 {
107     return IsValidEventName(env, params[0]) // 0 means the index of event name
108         && IsValidEventType(env, params[1]) // 1 means the index of event type
109         && IsValidEventParam(env, params[2]); // 2 means the index of event param
110 }
111 
IsNewWriteParams(const napi_env env,const napi_value params[],size_t len)112 bool NapiHiAppEventBuilder::IsNewWriteParams(const napi_env env, const napi_value params[], size_t len)
113 {
114     return IsValidEventInfo(env, params[0]);
115 }
116 
AddArrayParam2EventPack(napi_env env,const std::string & key,const napi_value arr)117 bool NapiHiAppEventBuilder::AddArrayParam2EventPack(napi_env env, const std::string &key,
118     const napi_value arr)
119 {
120     napi_valuetype type = NapiUtil::GetArrayType(env, arr);
121     switch (type) {
122         case napi_boolean: {
123             std::vector<bool> bools;
124             NapiUtil::GetBooleans(env, arr, bools);
125             appEventPack_->AddParam(key, bools);
126             break;
127         }
128         case napi_number: {
129             std::vector<double> doubles;
130             NapiUtil::GetDoubles(env, arr, doubles);
131             appEventPack_->AddParam(key, doubles);
132             break;
133         }
134         case napi_string: {
135             std::vector<std::string> strs;
136             NapiUtil::GetStrings(env, arr, strs);
137             appEventPack_->AddParam(key, strs);
138             break;
139         }
140         case napi_null: {
141             appEventPack_->AddParam(key);
142             break;
143         }
144         default: {
145             HILOG_ERROR(LOG_CORE, "array param value type is invalid");
146             result_ = ERROR_INVALID_LIST_PARAM_TYPE;
147             std::string errMsg = NapiUtil::CreateErrMsg("param value", PARAM_VALUE_TYPE);
148             NapiUtil::ThrowError(env, NapiError::ERR_PARAM, errMsg, isV9_);
149             return false;
150         }
151     }
152     return true;
153 }
154 
AddParam2EventPack(napi_env env,const std::string & key,const napi_value value)155 bool NapiHiAppEventBuilder::AddParam2EventPack(napi_env env, const std::string &key,
156     const napi_value value)
157 {
158     napi_valuetype type = NapiUtil::GetType(env, value);
159     switch (type) {
160         case napi_boolean:
161             appEventPack_->AddParam(key, NapiUtil::GetBoolean(env, value));
162             break;
163         case napi_number:
164             appEventPack_->AddParam(key, NapiUtil::GetDouble(env, value));
165             break;
166         case napi_string:
167             appEventPack_->AddParam(key, NapiUtil::GetString(env, value));
168             break;
169         case napi_object:
170             if (NapiUtil::IsArray(env, value)) {
171                 return AddArrayParam2EventPack(env, key, value);
172             }
173             [[fallthrough]];
174         default:
175             HILOG_ERROR(LOG_CORE, "param value type is invalid");
176             result_ = ERROR_INVALID_PARAM_VALUE_TYPE;
177             std::string errMsg = NapiUtil::CreateErrMsg("param value", PARAM_VALUE_TYPE);
178             NapiUtil::ThrowError(env, NapiError::ERR_PARAM, errMsg, isV9_);
179             return false;
180     }
181     return true;
182 }
183 
AddParams2EventPack(napi_env env,const napi_value paramObj)184 bool NapiHiAppEventBuilder::AddParams2EventPack(napi_env env, const napi_value paramObj)
185 {
186     std::vector<std::string> keys;
187     NapiUtil::GetPropertyNames(env, paramObj, keys);
188     for (auto key : keys) {
189         if (key.length() > MAX_LENGTH_OF_PARAM_NAME) {
190             result_ = ERROR_INVALID_PARAM_NAME;
191             HILOG_INFO(LOG_CORE, "the length=%{public}zu of the param key is invalid", key.length());
192             continue;
193         }
194         napi_value value = NapiUtil::GetProperty(env, paramObj, key);
195         if (value == nullptr) {
196             result_ = ERROR_INVALID_PARAM_VALUE_TYPE;
197             std::string errMsg = NapiUtil::CreateErrMsg("param value", PARAM_VALUE_TYPE);
198             NapiUtil::ThrowError(env, NapiError::ERR_PARAM, errMsg, isV9_);
199             return false;
200         }
201         if (!AddParam2EventPack(env, key, value)) {
202             return false;
203         }
204     }
205     return true;
206 }
207 
BuildEventPack(napi_env env,const napi_value params[])208 void NapiHiAppEventBuilder::BuildEventPack(napi_env env, const napi_value params[])
209 {
210     int index = 0;
211     std::string name = NapiUtil::GetString(env, params[index++]);
212     int32_t type = NapiUtil::GetInt32(env, params[index++]);
213     appEventPack_ = std::make_shared<AppEventPack>(name, type);
214     AddParams2EventPack(env, params[index]);
215 }
216 
BuildEventPack(napi_env env,const napi_value eventInfo)217 bool NapiHiAppEventBuilder::BuildEventPack(napi_env env, const napi_value eventInfo)
218 {
219     std::string domain = NapiUtil::GetString(env, NapiUtil::GetProperty(env, eventInfo, DOMAIN_PROPERTY));
220     std::string name = NapiUtil::GetString(env, NapiUtil::GetProperty(env, eventInfo, NAME_PROPERTY));
221     int32_t type = NapiUtil::GetInt32(env, NapiUtil::GetProperty(env, eventInfo, TYPE_PROPERTY));
222     appEventPack_ = std::make_shared<AppEventPack>(domain, name, type);
223     napi_value param = NapiUtil::GetProperty(env, eventInfo, PARAM_PROPERTY);
224     return AddParams2EventPack(env, param);
225 }
226 
BuildCallback(const napi_env env,const napi_value callback)227 void NapiHiAppEventBuilder::BuildCallback(const napi_env env, const napi_value callback)
228 {
229     if (NapiUtil::IsFunction(env, callback)) {
230         callback_ = NapiUtil::CreateReference(env, callback);
231     }
232 }
233 
Build(const napi_env env,const napi_value params[],size_t len)234 std::shared_ptr<AppEventPack> NapiHiAppEventBuilder::Build(const napi_env env, const napi_value params[], size_t len)
235 {
236     if (len < 3) { // the min number of params for write is 3
237         result_ = ERROR_INVALID_PARAM_NUM_JS;
238         return nullptr;
239     }
240 
241     // 1. build AppEventPack
242     if (IsOldWriteParams(env, params, len)) {
243         BuildEventPack(env, params);
244     } else {
245         result_ = ERROR_INVALID_PARAM_TYPE_JS;
246     }
247 
248     // 2. build callback if any
249     BuildCallback(env, params[len - 1]); // (len - 1) means the last param
250     return appEventPack_;
251 }
252 
BuildV9(const napi_env env,const napi_value params[],size_t len)253 std::shared_ptr<AppEventPack> NapiHiAppEventBuilder::BuildV9(const napi_env env, const napi_value params[], size_t len)
254 {
255     isV9_ = true;
256     if (len < 1) { // the min number of params for writeV9 is 1
257         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("info"), isV9_);
258         return nullptr;
259     }
260     if (!IsNewWriteParams(env, params, len)) {
261         return nullptr;
262     }
263     if (!BuildEventPack(env, params[0])) {
264         return nullptr;
265     }
266     BuildCallback(env, params[len - 1]); // (len - 1) means the last param
267     return appEventPack_;
268 }
269 
GetResult() const270 int NapiHiAppEventBuilder::GetResult() const
271 {
272     return result_;
273 }
274 
GetCallback() const275 napi_ref NapiHiAppEventBuilder::GetCallback() const
276 {
277     return callback_;
278 }
279 } // namespace HiviewDFX
280 } // namespace OHOS
281