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 #include "js_watcher.h"
17
18 #include <cstring>
19
20 #include "anonymous.h"
21 #include "js_common.h"
22 #include "js_util.h"
23 #include "logger.h"
24 #include "notifier_impl.h"
25 #include "objectstore_errors.h"
26
27 namespace OHOS::ObjectStore {
JSWatcher(const napi_env env,DistributedObjectStore * objectStore,DistributedObject * object)28 JSWatcher::JSWatcher(const napi_env env, DistributedObjectStore *objectStore, DistributedObject *object)
29 : UvQueue(env), env_(env), changeEventListener_(nullptr), statusEventListener_(nullptr)
30 {
31 }
32
~JSWatcher()33 JSWatcher::~JSWatcher()
34 {
35 delete changeEventListener_;
36 delete statusEventListener_;
37 changeEventListener_ = nullptr;
38 statusEventListener_ = nullptr;
39 }
40
On(const char * type,napi_value handler)41 bool JSWatcher::On(const char *type, napi_value handler)
42 {
43 EventListener *listener = Find(type);
44 if (listener == nullptr) {
45 LOG_ERROR("error type %{public}s", type);
46 return false;
47 }
48 return listener->Add(env_, handler);
49 }
50
Off(const char * type,napi_value handler)51 void JSWatcher::Off(const char *type, napi_value handler)
52 {
53 EventListener *listener = Find(type);
54 if (listener == nullptr) {
55 LOG_ERROR("error type %{public}s", type);
56 return;
57 }
58 if (handler == nullptr) {
59 listener->Clear(env_);
60 } else {
61 listener->Del(env_, handler);
62 }
63 }
ProcessChange(napi_env env,std::list<void * > & args)64 void JSWatcher::ProcessChange(napi_env env, std::list<void *> &args)
65 {
66 constexpr static int8_t ARGV_SIZE = 2;
67 napi_value callback = nullptr;
68 napi_value global = nullptr;
69 napi_value param[ARGV_SIZE];
70 napi_value result;
71 napi_status status = napi_get_global(env, &global);
72 NOT_MATCH_GOTO_ERROR(status == napi_ok);
73 for (auto item : args) {
74 ChangeArgs *changeArgs = static_cast<ChangeArgs *>(item);
75 status = napi_get_reference_value(env, changeArgs->callback_, &callback);
76 NOT_MATCH_GOTO_ERROR(status == napi_ok);
77 status = JSUtil::SetValue(env, changeArgs->sessionId_, param[0]);
78 NOT_MATCH_GOTO_ERROR(status == napi_ok);
79 JSUtil::SetValue(env, changeArgs->changeData_, param[1]);
80 NOT_MATCH_GOTO_ERROR(status == napi_ok);
81 LOG_INFO("start %{public}s, %{public}zu", changeArgs->sessionId_.c_str(), changeArgs->changeData_.size());
82 status = napi_call_function(env, global, callback, ARGV_SIZE, param, &result);
83 LOG_INFO("end %{public}s, %{public}zu", changeArgs->sessionId_.c_str(), changeArgs->changeData_.size());
84 NOT_MATCH_GOTO_ERROR(status == napi_ok);
85 }
86 ERROR:
87 for (auto item : args) {
88 ChangeArgs *changeArgs = static_cast<ChangeArgs *>(item);
89 delete changeArgs;
90 }
91 args.clear();
92 }
Emit(const char * type,const std::string & sessionId,const std::vector<std::string> & changeData)93 void JSWatcher::Emit(const char *type, const std::string &sessionId, const std::vector<std::string> &changeData)
94 {
95 if (changeData.empty()) {
96 LOG_ERROR("empty change");
97 return;
98 }
99 LOG_INFO("start %{public}s, %{public}s", sessionId.c_str(), changeData.at(0).c_str());
100 EventListener *listener = Find(type);
101 if (listener == nullptr) {
102 LOG_ERROR("error type %{public}s", type);
103 return;
104 }
105
106 for (EventHandler *handler = listener->handlers_; handler != nullptr; handler = handler->next) {
107 ChangeArgs *changeArgs = new (std::nothrow) ChangeArgs(handler->callbackRef, sessionId, changeData);
108 if (changeArgs == nullptr) {
109 LOG_ERROR("JSWatcher::Emit no memory for changeArgs malloc!");
110 return;
111 }
112 CallFunction(ProcessChange, changeArgs);
113 }
114 }
115
Find(const char * type)116 EventListener *JSWatcher::Find(const char *type)
117 {
118 if (!strcmp(Constants::CHANGE, type)) {
119 return changeEventListener_;
120 }
121 if (!strcmp(Constants::STATUS, type)) {
122 return statusEventListener_;
123 }
124 return nullptr;
125 }
126
ProcessStatus(napi_env env,std::list<void * > & args)127 void JSWatcher::ProcessStatus(napi_env env, std::list<void *> &args)
128 {
129 constexpr static int8_t ARGV_SIZE = 3;
130 napi_value callback = nullptr;
131 napi_value global = nullptr;
132 napi_value param[ARGV_SIZE];
133 napi_value result;
134 napi_status status = napi_get_global(env, &global);
135 NOT_MATCH_GOTO_ERROR(status == napi_ok);
136 for (auto item : args) {
137 StatusArgs *statusArgs = static_cast<StatusArgs *>(item);
138 status = napi_get_reference_value(env, statusArgs->callback_, &callback);
139 NOT_MATCH_GOTO_ERROR(status == napi_ok);
140 status = JSUtil::SetValue(env, statusArgs->sessionId_, param[0]);
141 NOT_MATCH_GOTO_ERROR(status == napi_ok);
142 status = JSUtil::SetValue(env, statusArgs->networkId_, param[1]);
143 NOT_MATCH_GOTO_ERROR(status == napi_ok);
144 status = JSUtil::SetValue(env, statusArgs->status_, param[2]);
145 NOT_MATCH_GOTO_ERROR(status == napi_ok);
146 LOG_INFO("start %{public}s, %{public}s, %{public}s", statusArgs->sessionId_.c_str(),
147 Anonymous::Change(statusArgs->networkId_).c_str(), statusArgs->status_.c_str());
148 status = napi_call_function(env, global, callback, ARGV_SIZE, param, &result);
149 LOG_INFO("end %{public}s, %{public}s, %{public}s", statusArgs->sessionId_.c_str(),
150 Anonymous::Change(statusArgs->networkId_).c_str(), statusArgs->status_.c_str());
151 NOT_MATCH_GOTO_ERROR(status == napi_ok);
152 }
153 ERROR:
154 LOG_DEBUG("do clear");
155 for (auto item : args) {
156 StatusArgs *statusArgs = static_cast<StatusArgs *>(item);
157 delete statusArgs;
158 }
159 args.clear();
160 }
161
Emit(const char * type,const std::string & sessionId,const std::string & networkId,const std::string & status)162 void JSWatcher::Emit(
163 const char *type, const std::string &sessionId, const std::string &networkId, const std::string &status)
164 {
165 if (sessionId.empty() || networkId.empty()) {
166 LOG_ERROR("empty %{public}s %{public}s", sessionId.c_str(), Anonymous::Change(networkId).c_str());
167 return;
168 }
169 LOG_INFO("status change %{public}s %{public}s", sessionId.c_str(), Anonymous::Change(networkId).c_str());
170 EventListener *listener = Find(type);
171 if (listener == nullptr) {
172 LOG_ERROR("error type %{public}s", type);
173 return;
174 }
175
176 for (EventHandler *handler = listener->handlers_; handler != nullptr; handler = handler->next) {
177 StatusArgs *changeArgs = new (std::nothrow) StatusArgs(handler->callbackRef, sessionId, networkId, status);
178 if (changeArgs == nullptr) {
179 LOG_ERROR("JSWatcher::Emit no memory for StatusArgs malloc!");
180 return;
181 }
182 CallFunction(ProcessStatus, changeArgs);
183 }
184 return;
185 }
186
IsEmpty()187 bool JSWatcher::IsEmpty()
188 {
189 if (changeEventListener_->IsEmpty() && statusEventListener_->IsEmpty()) {
190 return true;
191 }
192 return false;
193 }
194
SetListener(ChangeEventListener * changeEventListener,StatusEventListener * statusEventListener)195 void JSWatcher::SetListener(ChangeEventListener *changeEventListener, StatusEventListener *statusEventListener)
196 {
197 changeEventListener_ = changeEventListener;
198 statusEventListener_ = statusEventListener;
199 }
200
Find(napi_env env,napi_value handler)201 EventHandler *EventListener::Find(napi_env env, napi_value handler)
202 {
203 EventHandler *result = nullptr;
204 for (EventHandler *i = handlers_; i != nullptr; i = i->next) {
205 napi_value callback = nullptr;
206 napi_get_reference_value(env, i->callbackRef, &callback);
207 bool isEquals = false;
208 napi_strict_equals(env, handler, callback, &isEquals);
209 if (isEquals) {
210 result = i;
211 }
212 }
213 return result;
214 }
215
Clear(napi_env env)216 void EventListener::Clear(napi_env env)
217 {
218 for (EventHandler *i = handlers_; i != nullptr; i = handlers_) {
219 handlers_ = i->next;
220 napi_delete_reference(env, i->callbackRef);
221 delete i;
222 }
223 }
224
Del(napi_env env,napi_value handler)225 bool EventListener::Del(napi_env env, napi_value handler)
226 {
227 EventHandler *temp = nullptr;
228 napi_status status;
229 for (EventHandler *i = handlers_; i != nullptr;) {
230 napi_value callback = nullptr;
231 status = napi_get_reference_value(env, i->callbackRef, &callback);
232 if (status != napi_ok) {
233 LOG_ERROR("error! %{public}d", status);
234 return false;
235 }
236 bool isEquals = false;
237 napi_strict_equals(env, handler, callback, &isEquals);
238 if (isEquals) {
239 EventHandler *delData = i;
240 i = i->next;
241 if (temp == nullptr) {
242 handlers_ = delData->next;
243 } else {
244 temp->next = delData->next;
245 }
246 napi_delete_reference(env, delData->callbackRef);
247 delete delData;
248 } else {
249 temp = i;
250 i = i->next;
251 }
252 }
253 return handlers_ == nullptr;
254 }
255
Add(napi_env env,napi_value handler)256 bool EventListener::Add(napi_env env, napi_value handler)
257 {
258 if (Find(env, handler) != nullptr) {
259 LOG_ERROR("has added,return");
260 return false;
261 }
262
263 if (handlers_ == nullptr) {
264 handlers_ = new (std::nothrow) EventHandler();
265 if (handlers_ == nullptr) {
266 LOG_ERROR("EventListener::Add no memory for EventHandler malloc!");
267 return false;
268 }
269 handlers_->next = nullptr;
270 } else {
271 auto temp = new (std::nothrow) EventHandler();
272 if (temp == nullptr) {
273 LOG_ERROR("EventListener::Add no memory for EventHandler malloc!");
274 return false;
275 }
276 temp->next = handlers_;
277 handlers_ = temp;
278 }
279 napi_create_reference(env, handler, 1, &handlers_->callbackRef);
280 return true;
281 }
282
OnChanged(const std::string & sessionid,const std::vector<std::string> & changedData)283 void WatcherImpl::OnChanged(const std::string &sessionid, const std::vector<std::string> &changedData)
284 {
285 std::shared_ptr<JSWatcher> lockedWatcher = watcher_.lock();
286 if (lockedWatcher) {
287 lockedWatcher->Emit(Constants::CHANGE, sessionid, changedData);
288 } else {
289 LOG_ERROR("watcher expired");
290 }
291 }
292
~WatcherImpl()293 WatcherImpl::~WatcherImpl()
294 {
295 LOG_ERROR("destroy");
296 }
297
Add(napi_env env,napi_value handler)298 bool ChangeEventListener::Add(napi_env env, napi_value handler)
299 {
300 if (!isWatched_ && object_ != nullptr) {
301 std::shared_ptr<WatcherImpl> watcher = std::make_shared<WatcherImpl>(watcher_);
302 uint32_t ret = objectStore_->Watch(object_, watcher);
303 if (ret != SUCCESS) {
304 LOG_ERROR("Watch %{public}s error", object_->GetSessionId().c_str());
305 } else {
306 LOG_INFO("Watch %{public}s success", object_->GetSessionId().c_str());
307 isWatched_ = true;
308 }
309 }
310 return EventListener::Add(env, handler);
311 }
312
Del(napi_env env,napi_value handler)313 bool ChangeEventListener::Del(napi_env env, napi_value handler)
314 {
315 bool isEmpty = EventListener::Del(env, handler);
316 if (isEmpty && isWatched_ && object_ != nullptr) {
317 uint32_t ret = objectStore_->UnWatch(object_);
318 if (ret != SUCCESS) {
319 LOG_ERROR("UnWatch %{public}s error", object_->GetSessionId().c_str());
320 } else {
321 LOG_INFO("UnWatch %{public}s success", object_->GetSessionId().c_str());
322 isWatched_ = false;
323 }
324 }
325 return isEmpty;
326 }
327
Clear(napi_env env)328 void ChangeEventListener::Clear(napi_env env)
329 {
330 EventListener::Clear(env);
331 if (isWatched_ && object_ != nullptr) {
332 uint32_t ret = objectStore_->UnWatch(object_);
333 if (ret != SUCCESS) {
334 LOG_ERROR("UnWatch %{public}s error", object_->GetSessionId().c_str());
335 } else {
336 LOG_INFO("UnWatch %{public}s success", object_->GetSessionId().c_str());
337 isWatched_ = false;
338 }
339 }
340 }
341
ChangeEventListener(std::weak_ptr<JSWatcher> watcher,DistributedObjectStore * objectStore,DistributedObject * object)342 ChangeEventListener::ChangeEventListener(
343 std::weak_ptr<JSWatcher> watcher, DistributedObjectStore *objectStore, DistributedObject *object)
344 : objectStore_(objectStore), object_(object), watcher_(watcher)
345 {
346 }
347
Add(napi_env env,napi_value handler)348 bool StatusEventListener::Add(napi_env env, napi_value handler)
349 {
350 LOG_INFO("Add status watch %{public}s", sessionId_.c_str());
351 NotifierImpl::GetInstance()->AddWatcher(sessionId_, watcher_);
352 return EventListener::Add(env, handler);
353 }
354
Del(napi_env env,napi_value handler)355 bool StatusEventListener::Del(napi_env env, napi_value handler)
356 {
357 if (EventListener::Del(env, handler)) {
358 LOG_INFO("Del status watch %{public}s", sessionId_.c_str());
359 NotifierImpl::GetInstance()->DelWatcher(sessionId_);
360 return true;
361 }
362 return false;
363 }
364
Clear(napi_env env)365 void StatusEventListener::Clear(napi_env env)
366 {
367 NotifierImpl::GetInstance()->DelWatcher(sessionId_);
368 EventListener::Clear(env);
369 }
370
StatusEventListener(std::weak_ptr<JSWatcher> watcher,const std::string & sessionId)371 StatusEventListener::StatusEventListener(std::weak_ptr<JSWatcher> watcher, const std::string &sessionId)
372 : watcher_(watcher), sessionId_(sessionId)
373 {
374 }
375
ChangeArgs(const napi_ref callback,const std::string & sessionId,const std::vector<std::string> & changeData)376 JSWatcher::ChangeArgs::ChangeArgs(
377 const napi_ref callback, const std::string &sessionId, const std::vector<std::string> &changeData)
378 : callback_(callback), sessionId_(sessionId), changeData_(changeData)
379 {
380 }
381
StatusArgs(const napi_ref callback,const std::string & sessionId,const std::string & networkId,const std::string & status)382 JSWatcher::StatusArgs::StatusArgs(
383 const napi_ref callback, const std::string &sessionId, const std::string &networkId, const std::string &status)
384 : callback_(callback), sessionId_(sessionId), networkId_(networkId), status_(status)
385 {
386 }
387 } // namespace OHOS::ObjectStore
388