• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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_app_event_watcher.h"
16 
17 #include "hiappevent_base.h"
18 #include "hilog/log.h"
19 #include "napi_util.h"
20 #include "uv.h"
21 
22 namespace OHOS {
23 namespace HiviewDFX {
24 namespace {
25 const HiLogLabel LABEL = { LOG_CORE, HIAPPEVENT_DOMAIN, "Napi_HiAppEvent_Watcher" };
26 constexpr size_t CALLBACK_PARAM_NUM = 3;
27 constexpr size_t RECEIVE_PARAM_NUM = 2;
28 
SafeDeleteWork(uv_work_t * work)29 void SafeDeleteWork(uv_work_t* work)
30 {
31     if (work != nullptr) {
32         delete work;
33     }
34 }
35 }
OnTriggerContext()36 OnTriggerContext::OnTriggerContext()
37 {
38     env = nullptr;
39     onTrigger = nullptr;
40     holder = nullptr;
41     row = 0;
42     size = 0;
43 }
44 
~OnTriggerContext()45 OnTriggerContext::~OnTriggerContext()
46 {
47     if (onTrigger != nullptr) {
48         napi_delete_reference(env, onTrigger);
49     }
50     if (holder != nullptr) {
51         napi_delete_reference(env, holder);
52     }
53 }
54 
OnReceiveContext()55 OnReceiveContext::OnReceiveContext()
56 {
57     env = nullptr;
58     onReceive = nullptr;
59 }
60 
~OnReceiveContext()61 OnReceiveContext::~OnReceiveContext()
62 {
63     if (onReceive != nullptr) {
64         napi_delete_reference(env, onReceive);
65     }
66 }
67 
WatcherContext()68 WatcherContext::WatcherContext()
69 {
70     triggerContext = nullptr;
71     receiveContext = nullptr;
72 }
73 
~WatcherContext()74 WatcherContext::~WatcherContext()
75 {
76     if (triggerContext != nullptr) {
77         delete triggerContext;
78     }
79     if (receiveContext != nullptr) {
80         delete receiveContext;
81     }
82 }
83 
NapiAppEventWatcher(const std::string & name,const std::vector<AppEventFilter> & filters,TriggerCondition cond)84 NapiAppEventWatcher::NapiAppEventWatcher(
85     const std::string& name,
86     const std::vector<AppEventFilter>& filters,
87     TriggerCondition cond)
88     : AppEventWatcher(name, filters, cond), context_(nullptr)
89 {}
90 
~NapiAppEventWatcher()91 NapiAppEventWatcher::~NapiAppEventWatcher()
92 {
93     HiLog::Debug(LABEL, "start to destroy NapiAppEventWatcher object");
94     if (context_ == nullptr) {
95         return;
96     }
97     napi_env env = nullptr;
98     if (context_->receiveContext != nullptr) {
99         env = context_->receiveContext->env;
100     } else if (context_->triggerContext != nullptr) {
101         env = context_->triggerContext->env;
102     } else {
103         return;
104     }
105     uv_loop_t* loop = nullptr;
106     napi_get_uv_event_loop(env, &loop);
107     uv_work_t* work = new(std::nothrow) uv_work_t();
108     work->data = static_cast<void*>(context_);
109     uv_queue_work_with_qos(
110         loop,
111         work,
112         [](uv_work_t* work) {},
113         [](uv_work_t* work, int status) {
114             WatcherContext* context = static_cast<WatcherContext*>(work->data);
115             HiLog::Debug(LABEL, "start to destroy WatcherContext object");
116             delete context;
117             SafeDeleteWork(work);
118         },
119         uv_qos_default);
120 }
121 
InitHolder(const napi_env env,const napi_value holder)122 void NapiAppEventWatcher::InitHolder(const napi_env env, const napi_value holder)
123 {
124     if (context_ == nullptr) {
125         context_ = new(std::nothrow) WatcherContext();
126     }
127     if (context_->triggerContext == nullptr) {
128         context_->triggerContext = new(std::nothrow) OnTriggerContext();
129     }
130     context_->triggerContext->env = env;
131     context_->triggerContext->holder = NapiUtil::CreateReference(env, holder);
132 }
133 
OnTrigger(const TriggerCondition & triggerCond)134 void NapiAppEventWatcher::OnTrigger(const TriggerCondition& triggerCond)
135 {
136     HiLog::Debug(LABEL, "onTrigger start");
137     if (context_ == nullptr || context_->triggerContext == nullptr) {
138         HiLog::Error(LABEL, "onTrigger context is null");
139         return;
140     }
141     context_->triggerContext->row = triggerCond.row;
142     context_->triggerContext->size = triggerCond.size;
143 
144     uv_loop_t* loop = nullptr;
145     napi_get_uv_event_loop(context_->triggerContext->env, &loop);
146     uv_work_t* work = new(std::nothrow) uv_work_t();
147     work->data = static_cast<void*>(context_->triggerContext);
148     uv_queue_work_with_qos(
149         loop,
150         work,
151         [] (uv_work_t* work) {},
152         [] (uv_work_t* work, int status) {
153             auto context = static_cast<OnTriggerContext*>(work->data);
154             napi_handle_scope scope = nullptr;
155             napi_open_handle_scope(context->env, &scope);
156             if (scope == nullptr) {
157                 HiLog::Error(LABEL, "failed to open handle scope");
158                 SafeDeleteWork(work);
159                 return;
160             }
161             napi_value callback = NapiUtil::GetReferenceValue(context->env, context->onTrigger);
162             if (callback == nullptr) {
163                 HiLog::Error(LABEL, "failed to get callback from the context");
164                 SafeDeleteWork(work);
165                 napi_close_handle_scope(context->env, scope);
166                 return;
167             }
168             napi_value argv[CALLBACK_PARAM_NUM] = {
169                 NapiUtil::CreateInt32(context->env, context->row),
170                 NapiUtil::CreateInt32(context->env, context->size),
171                 NapiUtil::GetReferenceValue(context->env, context->holder)
172             };
173             napi_value ret = nullptr;
174             if (napi_call_function(context->env, nullptr, callback, CALLBACK_PARAM_NUM, argv, &ret) != napi_ok) {
175                 HiLog::Error(LABEL, "failed to call onTrigger function");
176             }
177             napi_close_handle_scope(context->env, scope);
178             SafeDeleteWork(work);
179         },
180         uv_qos_default);
181 }
182 
InitTrigger(const napi_env env,const napi_value triggerFunc)183 void NapiAppEventWatcher::InitTrigger(const napi_env env, const napi_value triggerFunc)
184 {
185     HiLog::Debug(LABEL, "start to init OnTrigger");
186     if (context_ == nullptr) {
187         context_ = new(std::nothrow) WatcherContext();
188     }
189     if (context_->triggerContext == nullptr) {
190         context_->triggerContext = new(std::nothrow) OnTriggerContext();
191     }
192     context_->triggerContext->env = env;
193     context_->triggerContext->onTrigger = NapiUtil::CreateReference(env, triggerFunc);
194 }
195 
InitReceiver(const napi_env env,const napi_value receiveFunc)196 void NapiAppEventWatcher::InitReceiver(const napi_env env, const napi_value receiveFunc)
197 {
198     HiLog::Debug(LABEL, "start to init onReceive");
199     if (context_ == nullptr) {
200         context_ = new(std::nothrow) WatcherContext();
201     }
202     if (context_->receiveContext == nullptr) {
203         context_->receiveContext = new(std::nothrow) OnReceiveContext();
204     }
205     context_->receiveContext->env = env;
206     context_->receiveContext->onReceive = NapiUtil::CreateReference(env, receiveFunc);
207 }
208 
OnEvents(const std::vector<std::shared_ptr<AppEventPack>> & events)209 void NapiAppEventWatcher::OnEvents(const std::vector<std::shared_ptr<AppEventPack>>& events)
210 {
211     HiLog::Debug(LABEL, "onEvents start");
212     if (context_ == nullptr || context_->receiveContext == nullptr) {
213         HiLog::Error(LABEL, "onReceive context is null");
214         return;
215     }
216     if (events.empty()) {
217         return;
218     }
219     context_->receiveContext->domain = events[0]->GetDomain();
220     context_->receiveContext->events = events;
221 
222     uv_loop_t* loop = nullptr;
223     napi_get_uv_event_loop(context_->receiveContext->env, &loop);
224     uv_work_t* work = new(std::nothrow) uv_work_t();
225     work->data = static_cast<void*>(context_->receiveContext);
226     uv_queue_work_with_qos(
227         loop,
228         work,
229         [] (uv_work_t* work) {},
230         [] (uv_work_t* work, int status) {
231             auto context = static_cast<OnReceiveContext*>(work->data);
232             napi_handle_scope scope = nullptr;
233             napi_open_handle_scope(context->env, &scope);
234             if (scope == nullptr) {
235                 HiLog::Error(LABEL, "failed to open handle scope");
236                 SafeDeleteWork(work);
237                 return;
238             }
239             napi_value callback = NapiUtil::GetReferenceValue(context->env, context->onReceive);
240             if (callback == nullptr) {
241                 HiLog::Error(LABEL, "failed to get callback from the context");
242                 SafeDeleteWork(work);
243                 napi_close_handle_scope(context->env, scope);
244                 return;
245             }
246             napi_value argv[RECEIVE_PARAM_NUM] = {
247                 NapiUtil::CreateString(context->env, context->domain),
248                 NapiUtil::CreateEventGroups(context->env, context->events)
249             };
250             napi_value ret = nullptr;
251             if (napi_call_function(context->env, nullptr, callback, RECEIVE_PARAM_NUM, argv, &ret) != napi_ok) {
252                 HiLog::Error(LABEL, "failed to call onReceive function");
253             }
254             napi_close_handle_scope(context->env, scope);
255             SafeDeleteWork(work);
256         },
257         uv_qos_default);
258 }
259 
IsRealTimeEvent(std::shared_ptr<AppEventPack> event)260 bool NapiAppEventWatcher::IsRealTimeEvent(std::shared_ptr<AppEventPack> event)
261 {
262     return (context_ != nullptr && context_->receiveContext != nullptr);
263 }
264 } // namespace HiviewDFX
265 } // namespace OHOS
266