• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "napi_hiappevent_watch.h"
16 
17 #include <string>
18 
19 #include "app_event_cache.h"
20 #include "app_event_watcher_mgr.h"
21 #include "hiappevent_base.h"
22 #include "hiappevent_config.h"
23 #include "hiappevent_verify.h"
24 #include "hilog/log.h"
25 #include "napi_app_event_holder.h"
26 #include "napi_app_event_watcher.h"
27 #include "napi_error.h"
28 #include "napi_util.h"
29 
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace NapiHiAppEventWatch {
33 namespace {
34 constexpr HiLogLabel LABEL = { LOG_CORE, HIAPPEVENT_DOMAIN, "Napi_HiAppEvent_Watch" };
35 const std::string NAME_PROPERTY = "name";
36 const std::string COND_PROPERTY = "triggerCondition";
37 const std::string COND_PROPS[] = { "row", "size", "timeOut" };
38 const std::string FILTERS_PROPERTY = "appEventFilters";
39 const std::string FILTERS_DOAMIN_PROP = "domain";
40 const std::string FILTERS_TYPES_PROP = "eventTypes";
41 const std::string TRIGGER_PROPERTY = "onTrigger";
42 constexpr int BIT_MASK = 1;
43 constexpr unsigned int BIT_ALL_TYPES = 0xff;
44 
IsValidName(const napi_env env,const napi_value name)45 bool IsValidName(const napi_env env, const napi_value name)
46 {
47     if (name == nullptr) {
48         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(NAME_PROPERTY));
49         return false;
50     }
51     if (!NapiUtil::IsString(env, name)) {
52         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(NAME_PROPERTY, "string"));
53         return false;
54     }
55     if (!IsValidWatcherName(NapiUtil::GetString(env, name))) {
56         NapiUtil::ThrowError(env, NapiError::ERR_INVALID_WATCHER_NAME, "Invalid watcher name.");
57         return false;
58     }
59     return true;
60 }
61 
IsValidCondition(const napi_env env,const napi_value cond)62 bool IsValidCondition(const napi_env env, const napi_value cond)
63 {
64     if (cond == nullptr) {
65         return true;
66     }
67     if (!NapiUtil::IsObject(env, cond)) {
68         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(COND_PROPERTY, "TriggerCondition"));
69         return false;
70     }
71     for (auto& propName : COND_PROPS) {
72         napi_value propValue = NapiUtil::GetProperty(env, cond, propName);
73         if (propValue == nullptr) {
74             continue;
75         }
76         if (!NapiUtil::IsNumber(env, propValue)) {
77             NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(propName, "number"));
78             return false;
79         }
80     }
81     return true;
82 }
83 
IsValidFilter(const napi_env env,const napi_value filter)84 bool IsValidFilter(const napi_env env, const napi_value filter)
85 {
86     napi_value domain = NapiUtil::GetProperty(env, filter, FILTERS_DOAMIN_PROP);
87     if (domain == nullptr) {
88         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_DOAMIN_PROP));
89         return false;
90     }
91     if (!NapiUtil::IsString(env, domain)) {
92         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_DOAMIN_PROP, "string"));
93         return false;
94     }
95     if (!IsValidDomain(NapiUtil::GetString(env, domain))) {
96         NapiUtil::ThrowError(env, NapiError::ERR_INVALID_FILTER_DOMAIN, "Invalid filtering event domain.");
97         return false;
98     }
99     napi_value types = NapiUtil::GetProperty(env, filter, FILTERS_TYPES_PROP);
100     if (types == nullptr) {
101         return true;
102     }
103     if (!NapiUtil::IsArrayType(env, types, napi_number)) {
104         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_TYPES_PROP, "EventType[]"));
105         return false;
106     }
107     return true;
108 }
109 
110 
IsValidFilters(const napi_env env,const napi_value filters)111 bool IsValidFilters(const napi_env env, const napi_value filters)
112 {
113     if (filters == nullptr) {
114         return true;
115     }
116     if (!NapiUtil::IsArrayType(env, filters, napi_object)) {
117         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(FILTERS_PROPERTY, "AppEventFilter[]"));
118         return false;
119     }
120 
121     size_t len = NapiUtil::GetArrayLength(env, filters);
122     for (size_t i = 0; i < len; i++) {
123         napi_value filter = NapiUtil::GetElement(env, filters, i);
124         if (!IsValidFilter(env, filter)) {
125             return false;
126         }
127     }
128     return true;
129 }
130 
IsValidTrigger(const napi_env env,const napi_value trigger)131 bool IsValidTrigger(const napi_env env, const napi_value trigger)
132 {
133     if (trigger == nullptr) {
134         return true;
135     }
136     if (!NapiUtil::IsFunction(env, trigger)) {
137         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(TRIGGER_PROPERTY, "function"));
138         return false;
139     }
140     return true;
141 }
142 
IsValidWatcher(const napi_env env,const napi_value watcher)143 bool IsValidWatcher(const napi_env env, const napi_value watcher)
144 {
145     if (!NapiUtil::IsObject(env, watcher)) {
146         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("watcher", "Watcher"));
147         return false;
148     }
149     return IsValidName(env, NapiUtil::GetProperty(env, watcher, NAME_PROPERTY))
150         && IsValidCondition(env, NapiUtil::GetProperty(env, watcher, COND_PROPERTY))
151         && IsValidFilters(env, NapiUtil::GetProperty(env, watcher, FILTERS_PROPERTY))
152         && IsValidTrigger(env, NapiUtil::GetProperty(env, watcher, TRIGGER_PROPERTY));
153 }
154 
GetConditionValue(const napi_env env,const napi_value cond,const std::string & name)155 int GetConditionValue(const napi_env env, const napi_value cond, const std::string& name)
156 {
157     if (auto value = NapiUtil::GetProperty(env, cond, name); value != nullptr) {
158         return NapiUtil::GetInt32(env, value);
159     }
160     return 0;
161 }
162 
GetName(const napi_env env,const napi_value watcher)163 std::string GetName(const napi_env env, const napi_value watcher)
164 {
165     return NapiUtil::GetString(env, NapiUtil::GetProperty(env, watcher, NAME_PROPERTY));
166 }
167 
GetCondition(const napi_env env,const napi_value watcher)168 TriggerCondition GetCondition(const napi_env env, const napi_value watcher)
169 {
170     TriggerCondition resCond = {
171         .row = 0,
172         .size = 0,
173         .timeOut = 0
174     };
175     napi_value cond = NapiUtil::GetProperty(env, watcher, COND_PROPERTY);
176     if (cond == nullptr) {
177         return resCond;
178     }
179 
180     size_t index = 0;
181     int row = GetConditionValue(env, cond, COND_PROPS[index++]);
182     if (row < 0) {
183         NapiUtil::ThrowError(env, NapiError::ERR_INVALID_COND_ROW, "Invalid row value.");
184         return resCond;
185     }
186 
187     resCond.row = row;
188     int size = GetConditionValue(env, cond, COND_PROPS[index++]);
189     if (size < 0) {
190         NapiUtil::ThrowError(env, NapiError::ERR_INVALID_COND_SIZE, "Invalid size value.");
191         return resCond;
192     }
193 
194     resCond.size = size;
195     int timeOut = GetConditionValue(env, cond, COND_PROPS[index++]);
196     if (timeOut < 0) {
197         NapiUtil::ThrowError(env, NapiError::ERR_INVALID_COND_TIMEOUT, "Invalid timeout value.");
198         return resCond;
199     }
200     return resCond;
201 }
202 
GetFilters(const napi_env env,const napi_value watcher,std::map<std::string,unsigned int> & filters)203 void GetFilters(const napi_env env, const napi_value watcher, std::map<std::string, unsigned int>& filters)
204 {
205     napi_value filtersValue = NapiUtil::GetProperty(env, watcher, FILTERS_PROPERTY);
206     if (filtersValue == nullptr) {
207         return;
208     }
209     size_t len = NapiUtil::GetArrayLength(env, filtersValue);
210     for (size_t i = 0; i < len; i++) {
211         napi_value filterValue = NapiUtil::GetElement(env, filtersValue, i);
212         std::string domain = NapiUtil::GetString(env, NapiUtil::GetProperty(env, filterValue, FILTERS_DOAMIN_PROP));
213         napi_value typesValue = NapiUtil::GetProperty(env, filterValue, FILTERS_TYPES_PROP);
214         if (typesValue == nullptr) {
215             filters[domain] = BIT_ALL_TYPES;
216             continue;
217         }
218         std::vector<int> types;
219         NapiUtil::GetInt32s(env, typesValue, types);
220         unsigned int filterType = 0;
221         for (auto type : types) {
222             if (!IsValidEventType(type)) {
223                 std::string errMsg = NapiUtil::CreateErrMsg(FILTERS_TYPES_PROP, "EventType[]");
224                 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, errMsg);
225                 continue;
226             }
227             filterType |= (BIT_MASK << type);
228         }
229         filters[domain] = filterType > 0 ? filterType : BIT_ALL_TYPES;
230     }
231 }
232 
CreateHolder(const napi_env env,const napi_value watcherName)233 napi_value CreateHolder(const napi_env env, const napi_value watcherName)
234 {
235     napi_value constructor = nullptr;
236     if (napi_get_reference_value(env, NapiAppEventHolder::constructor_, &constructor) != napi_ok) {
237         HiLog::Error(LABEL, "failed to get constructor of the holder");
238         return NapiUtil::CreateNull(env);
239     }
240     napi_value holder = nullptr;
241     if (napi_new_instance(env, constructor, 1, &watcherName, &holder) != napi_ok) { // param num is 1
242         HiLog::Error(LABEL, "failed to get new instance for holder");
243         return NapiUtil::CreateNull(env);
244     }
245     return holder;
246 }
247 }
248 
AddWatcher(const napi_env env,const napi_value watcher)249 napi_value AddWatcher(const napi_env env, const napi_value watcher)
250 {
251     if (!IsValidWatcher(env, watcher)) {
252         HiLog::Error(LABEL, "invalid watcher");
253         return NapiUtil::CreateNull(env);
254     }
255 
256     // 1. if DB is not opened, need to open DB first
257     if (!AppEventCache::GetInstance()->IsOpen()) {
258         std::string dir = HiAppEventConfig::GetInstance().GetStorageDir();
259         if (dir.empty() || AppEventCache::GetInstance()->Open(dir) != 0) {
260             HiLog::Error(LABEL, "failed to open db");
261             return NapiUtil::CreateNull(env);
262         }
263     }
264 
265     // 2. build watcher object
266     std::map<std::string, unsigned int> filters;
267     GetFilters(env, watcher, filters);
268     std::string name = GetName(env, watcher);
269     TriggerCondition cond = GetCondition(env, watcher);
270     auto watcherPtr = std::make_shared<NapiAppEventWatcher>(name, filters, cond);
271 
272     // 3. create holder and add holder to the watcher
273     napi_value holder = CreateHolder(env, NapiUtil::GetProperty(env, watcher, NAME_PROPERTY));
274     watcherPtr->InitHolder(env, holder);
275 
276     // 4. set trigger if any
277     napi_value trigger = NapiUtil::GetProperty(env, watcher, TRIGGER_PROPERTY);
278     if (trigger != nullptr) {
279         watcherPtr->InitTrigger(env, trigger);
280     }
281 
282     // 5. add the watcher to watcherManager
283     AppEventWatcherMgr::GetInstance()->AddWatcher(watcherPtr);
284     return holder;
285 }
286 
RemoveWatcher(const napi_env env,const napi_value watcher)287 napi_value RemoveWatcher(const napi_env env, const napi_value watcher)
288 {
289     if (!NapiUtil::IsObject(env, watcher)) {
290         NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("watcher", "Watcher"));
291         return NapiUtil::CreateUndefined(env);
292     }
293     if (!IsValidName(env, NapiUtil::GetProperty(env, watcher, NAME_PROPERTY))) {
294         return NapiUtil::CreateUndefined(env);
295     }
296     AppEventWatcherMgr::GetInstance()->RemoveWatcher(GetName(env, watcher));
297     return NapiUtil::CreateUndefined(env);
298 }
299 } // namespace NapiHiAppEventConfig
300 } // namespace HiviewDFX
301 } // namespace OHOS
302