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 "anonymous.h"
17 #include "js_common.h"
18 #include "js_util.h"
19 #include "logger.h"
20 #include "notifier_impl.h"
21 #include "objectstore_errors.h"
22 #include "progress_notifier_impl.h"
23
24 namespace OHOS::ObjectStore {
JSWatcher(const napi_env env,DistributedObjectStore * objectStore,DistributedObject * object)25 JSWatcher::JSWatcher(const napi_env env, DistributedObjectStore *objectStore, DistributedObject *object)
26 : UvQueue(env), env_(env), changeEventListener_(nullptr), statusEventListener_(nullptr),
27 progressEventListener_(nullptr)
28 {
29 }
30
~JSWatcher()31 JSWatcher::~JSWatcher()
32 {
33 delete changeEventListener_;
34 delete statusEventListener_;
35 delete progressEventListener_;
36 changeEventListener_ = nullptr;
37 statusEventListener_ = nullptr;
38 progressEventListener_ = 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", Anonymous::Change(changeArgs->sessionId_).c_str(),
82 changeArgs->changeData_.size());
83 status = napi_call_function(env, global, callback, ARGV_SIZE, param, &result);
84 LOG_INFO("end %{public}s, %{public}zu", Anonymous::Change(changeArgs->sessionId_).c_str(),
85 changeArgs->changeData_.size());
86 NOT_MATCH_GOTO_ERROR(status == napi_ok);
87 }
88 ERROR:
89 for (auto item : args) {
90 ChangeArgs *changeArgs = static_cast<ChangeArgs *>(item);
91 delete changeArgs;
92 }
93 args.clear();
94 }
Emit(const char * type,const std::string & sessionId,const std::vector<std::string> & changeData)95 void JSWatcher::Emit(const char *type, const std::string &sessionId, const std::vector<std::string> &changeData)
96 {
97 if (changeData.empty()) {
98 LOG_ERROR("empty change");
99 return;
100 }
101 LOG_INFO("start %{public}s, %{public}s", Anonymous::Change(sessionId).c_str(), changeData.at(0).c_str());
102 EventListener *listener = Find(type);
103 if (listener == nullptr) {
104 LOG_ERROR("error type %{public}s", type);
105 return;
106 }
107
108 for (EventHandler *handler = listener->handlers_; handler != nullptr; handler = handler->next) {
109 ChangeArgs *changeArgs = new (std::nothrow) ChangeArgs(handler->callbackRef, sessionId, changeData);
110 if (changeArgs == nullptr) {
111 LOG_ERROR("JSWatcher::Emit no memory for changeArgs malloc!");
112 return;
113 }
114 if (!CallFunction(ProcessChange, changeArgs)) {
115 delete changeArgs;
116 changeArgs = nullptr;
117 }
118 }
119 }
120
Find(const char * type)121 EventListener *JSWatcher::Find(const char *type)
122 {
123 if (!strcmp(Constants::CHANGE, type)) {
124 return changeEventListener_;
125 }
126 if (!strcmp(Constants::STATUS, type)) {
127 return statusEventListener_;
128 }
129 if (!strcmp(Constants::PROGRESS, type)) {
130 return progressEventListener_;
131 }
132 return nullptr;
133 }
134
ProcessStatus(napi_env env,std::list<void * > & args)135 void JSWatcher::ProcessStatus(napi_env env, std::list<void *> &args)
136 {
137 constexpr static int8_t ARGV_SIZE = 3;
138 napi_value callback = nullptr;
139 napi_value global = nullptr;
140 napi_value param[ARGV_SIZE];
141 napi_value result;
142 napi_status status = napi_get_global(env, &global);
143 NOT_MATCH_GOTO_ERROR(status == napi_ok);
144 for (auto item : args) {
145 StatusArgs *statusArgs = static_cast<StatusArgs *>(item);
146 status = napi_get_reference_value(env, statusArgs->callback_, &callback);
147 NOT_MATCH_GOTO_ERROR(status == napi_ok);
148 status = JSUtil::SetValue(env, statusArgs->sessionId_, param[0]);
149 NOT_MATCH_GOTO_ERROR(status == napi_ok);
150 status = JSUtil::SetValue(env, statusArgs->networkId_, param[1]);
151 NOT_MATCH_GOTO_ERROR(status == napi_ok);
152 status = JSUtil::SetValue(env, statusArgs->status_, param[2]);
153 NOT_MATCH_GOTO_ERROR(status == napi_ok);
154 LOG_INFO("start %{public}s, %{public}s, %{public}s", Anonymous::Change(statusArgs->sessionId_).c_str(),
155 Anonymous::Change(statusArgs->networkId_).c_str(), statusArgs->status_.c_str());
156 status = napi_call_function(env, global, callback, ARGV_SIZE, param, &result);
157 LOG_INFO("end %{public}s, %{public}s, %{public}s", Anonymous::Change(statusArgs->sessionId_).c_str(),
158 Anonymous::Change(statusArgs->networkId_).c_str(), statusArgs->status_.c_str());
159 NOT_MATCH_GOTO_ERROR(status == napi_ok);
160 }
161 ERROR:
162 LOG_DEBUG("do clear");
163 for (auto item : args) {
164 StatusArgs *statusArgs = static_cast<StatusArgs *>(item);
165 delete statusArgs;
166 }
167 args.clear();
168 }
169
Emit(const char * type,const std::string & sessionId,const std::string & networkId,const std::string & status)170 void JSWatcher::Emit(
171 const char *type, const std::string &sessionId, const std::string &networkId, const std::string &status)
172 {
173 if (sessionId.empty() || networkId.empty()) {
174 LOG_ERROR("empty %{public}s %{public}s", Anonymous::Change(sessionId).c_str(),
175 Anonymous::Change(networkId).c_str());
176 return;
177 }
178 LOG_INFO("status change %{public}s %{public}s", Anonymous::Change(sessionId).c_str(),
179 Anonymous::Change(networkId).c_str());
180 EventListener *listener = Find(type);
181 if (listener == nullptr) {
182 LOG_ERROR("error type %{public}s", type);
183 return;
184 }
185
186 for (EventHandler *handler = listener->handlers_; handler != nullptr; handler = handler->next) {
187 StatusArgs *changeArgs = new (std::nothrow) StatusArgs(handler->callbackRef, sessionId, networkId, status);
188 if (changeArgs == nullptr) {
189 LOG_ERROR("JSWatcher::Emit no memory for StatusArgs malloc!");
190 return;
191 }
192 if (!CallFunction(ProcessStatus, changeArgs)) {
193 delete changeArgs;
194 changeArgs = nullptr;
195 }
196 }
197 return;
198 }
199
ProcessProgress(napi_env env,std::list<void * > & args)200 void JSWatcher::ProcessProgress(napi_env env, std::list<void *> &args)
201 {
202 constexpr static int8_t ARGV_SIZE = 2;
203 napi_value callback = nullptr;
204 napi_value global = nullptr;
205 napi_value param[ARGV_SIZE];
206 napi_value result;
207 napi_status status = napi_get_global(env, &global);
208 NOT_MATCH_GOTO_ERROR(status == napi_ok);
209 for (auto item : args) {
210 ProgressArgs *progressArgs = static_cast<ProgressArgs *>(item);
211 status = napi_get_reference_value(env, progressArgs->callback_, &callback);
212 NOT_MATCH_GOTO_ERROR(status == napi_ok);
213 status = JSUtil::SetValue(env, progressArgs->sessionId_, param[0]);
214 NOT_MATCH_GOTO_ERROR(status == napi_ok);
215 status = JSUtil::SetValue(env, static_cast<uint32_t>(progressArgs->progress_), param[1]);
216 NOT_MATCH_GOTO_ERROR(status == napi_ok);
217 LOG_INFO("start %{public}s, %{public}d", Anonymous::Change(progressArgs->sessionId_).c_str(),
218 progressArgs->progress_);
219 status = napi_call_function(env, global, callback, ARGV_SIZE, param, &result);
220 LOG_INFO("end %{public}s, %{public}d", Anonymous::Change(progressArgs->sessionId_).c_str(),
221 progressArgs->progress_);
222 NOT_MATCH_GOTO_ERROR(status == napi_ok);
223 }
224 ERROR:
225 LOG_DEBUG("do clear");
226 for (auto item : args) {
227 ProgressArgs *progressArgs = static_cast<ProgressArgs *>(item);
228 delete progressArgs;
229 }
230 args.clear();
231 }
232
Emit(const char * type,const std::string & sessionId,int32_t progress)233 void JSWatcher::Emit(const char *type, const std::string &sessionId, int32_t progress)
234 {
235 if (sessionId.empty()) {
236 LOG_ERROR("empty sessionId %{public}s", Anonymous::Change(sessionId).c_str());
237 return;
238 }
239 LOG_INFO("progress change %{public}s %{public}d", Anonymous::Change(sessionId).c_str(), progress);
240 EventListener *listener = Find(type);
241 if (listener == nullptr) {
242 LOG_ERROR("error type %{public}s", type);
243 return;
244 }
245
246 for (EventHandler *handler = listener->handlers_; handler != nullptr; handler = handler->next) {
247 ProgressArgs *progressArgs = new (std::nothrow) ProgressArgs(handler->callbackRef, sessionId, progress);
248 if (progressArgs == nullptr) {
249 LOG_ERROR("JSWatcher::Emit no memory for ProgressArgs malloc!");
250 return;
251 }
252 if (!CallFunction(ProcessProgress, progressArgs)) {
253 delete progressArgs;
254 progressArgs = nullptr;
255 }
256 }
257 return;
258 }
259
IsEmpty()260 bool JSWatcher::IsEmpty()
261 {
262 if (changeEventListener_->IsEmpty() && statusEventListener_->IsEmpty() && progressEventListener_->IsEmpty()) {
263 return true;
264 }
265 return false;
266 }
267
SetListener(ChangeEventListener * changeEventListener,StatusEventListener * statusEventListener,ProgressEventListener * progressEventListener)268 void JSWatcher::SetListener(ChangeEventListener *changeEventListener, StatusEventListener *statusEventListener,
269 ProgressEventListener *progressEventListener)
270 {
271 changeEventListener_ = changeEventListener;
272 statusEventListener_ = statusEventListener;
273 progressEventListener_ = progressEventListener;
274 }
275
Find(napi_env env,napi_value handler)276 EventHandler *EventListener::Find(napi_env env, napi_value handler)
277 {
278 EventHandler *result = nullptr;
279 for (EventHandler *i = handlers_; i != nullptr; i = i->next) {
280 napi_value callback = nullptr;
281 napi_get_reference_value(env, i->callbackRef, &callback);
282 bool isEquals = false;
283 napi_strict_equals(env, handler, callback, &isEquals);
284 if (isEquals) {
285 result = i;
286 }
287 }
288 return result;
289 }
290
Clear(napi_env env)291 void EventListener::Clear(napi_env env)
292 {
293 for (EventHandler *i = handlers_; i != nullptr; i = handlers_) {
294 handlers_ = i->next;
295 napi_delete_reference(env, i->callbackRef);
296 delete i;
297 }
298 }
299
Del(napi_env env,napi_value handler)300 bool EventListener::Del(napi_env env, napi_value handler)
301 {
302 EventHandler *temp = nullptr;
303 napi_status status;
304 for (EventHandler *i = handlers_; i != nullptr;) {
305 napi_value callback = nullptr;
306 status = napi_get_reference_value(env, i->callbackRef, &callback);
307 if (status != napi_ok) {
308 LOG_ERROR("error! %{public}d", status);
309 return false;
310 }
311 bool isEquals = false;
312 napi_strict_equals(env, handler, callback, &isEquals);
313 if (isEquals) {
314 EventHandler *delData = i;
315 i = i->next;
316 if (temp == nullptr) {
317 handlers_ = delData->next;
318 } else {
319 temp->next = delData->next;
320 }
321 napi_delete_reference(env, delData->callbackRef);
322 delete delData;
323 } else {
324 temp = i;
325 i = i->next;
326 }
327 }
328 return handlers_ == nullptr;
329 }
330
Add(napi_env env,napi_value handler)331 bool EventListener::Add(napi_env env, napi_value handler)
332 {
333 if (Find(env, handler) != nullptr) {
334 LOG_ERROR("has added,return");
335 return false;
336 }
337
338 if (handlers_ == nullptr) {
339 handlers_ = new (std::nothrow) EventHandler();
340 if (handlers_ == nullptr) {
341 LOG_ERROR("EventListener::Add no memory for EventHandler malloc!");
342 return false;
343 }
344 handlers_->next = nullptr;
345 } else {
346 auto temp = new (std::nothrow) EventHandler();
347 if (temp == nullptr) {
348 LOG_ERROR("EventListener::Add no memory for EventHandler malloc!");
349 return false;
350 }
351 temp->next = handlers_;
352 handlers_ = temp;
353 }
354 napi_create_reference(env, handler, 1, &handlers_->callbackRef);
355 return true;
356 }
357
OnChanged(const std::string & sessionid,const std::vector<std::string> & changedData)358 void WatcherImpl::OnChanged(const std::string &sessionid, const std::vector<std::string> &changedData)
359 {
360 std::shared_ptr<JSWatcher> lockedWatcher = watcher_.lock();
361 if (lockedWatcher) {
362 lockedWatcher->Emit(Constants::CHANGE, sessionid, changedData);
363 } else {
364 LOG_ERROR("watcher expired");
365 }
366 }
367
~WatcherImpl()368 WatcherImpl::~WatcherImpl()
369 {
370 LOG_ERROR("destroy");
371 }
372
Add(napi_env env,napi_value handler)373 bool ChangeEventListener::Add(napi_env env, napi_value handler)
374 {
375 if (!isWatched_ && object_ != nullptr) {
376 std::shared_ptr<WatcherImpl> watcher = std::make_shared<WatcherImpl>(watcher_);
377 uint32_t ret = objectStore_->Watch(object_, watcher);
378 if (ret != SUCCESS) {
379 LOG_ERROR("Watch %{public}s error", Anonymous::Change(object_->GetSessionId()).c_str());
380 } else {
381 LOG_INFO("Watch %{public}s success", Anonymous::Change(object_->GetSessionId()).c_str());
382 isWatched_ = true;
383 }
384 }
385 return EventListener::Add(env, handler);
386 }
387
Del(napi_env env,napi_value handler)388 bool ChangeEventListener::Del(napi_env env, napi_value handler)
389 {
390 bool isEmpty = EventListener::Del(env, handler);
391 if (isEmpty && isWatched_ && object_ != nullptr) {
392 uint32_t ret = objectStore_->UnWatch(object_);
393 if (ret != SUCCESS) {
394 LOG_ERROR("UnWatch %{public}s error", Anonymous::Change(object_->GetSessionId()).c_str());
395 } else {
396 LOG_INFO("UnWatch %{public}s success", Anonymous::Change(object_->GetSessionId()).c_str());
397 isWatched_ = false;
398 }
399 }
400 return isEmpty;
401 }
402
Clear(napi_env env)403 void ChangeEventListener::Clear(napi_env env)
404 {
405 EventListener::Clear(env);
406 if (isWatched_ && object_ != nullptr) {
407 uint32_t ret = objectStore_->UnWatch(object_);
408 if (ret != SUCCESS) {
409 LOG_ERROR("UnWatch %{public}s error", Anonymous::Change(object_->GetSessionId()).c_str());
410 } else {
411 LOG_INFO("UnWatch %{public}s success", Anonymous::Change(object_->GetSessionId()).c_str());
412 isWatched_ = false;
413 }
414 }
415 }
416
ChangeEventListener(std::weak_ptr<JSWatcher> watcher,DistributedObjectStore * objectStore,DistributedObject * object)417 ChangeEventListener::ChangeEventListener(
418 std::weak_ptr<JSWatcher> watcher, DistributedObjectStore *objectStore, DistributedObject *object)
419 : objectStore_(objectStore), object_(object), watcher_(watcher)
420 {
421 }
422
Add(napi_env env,napi_value handler)423 bool StatusEventListener::Add(napi_env env, napi_value handler)
424 {
425 LOG_INFO("Add status watch %{public}s", Anonymous::Change(sessionId_).c_str());
426 NotifierImpl::GetInstance()->AddWatcher(sessionId_, watcher_);
427 return EventListener::Add(env, handler);
428 }
429
Del(napi_env env,napi_value handler)430 bool StatusEventListener::Del(napi_env env, napi_value handler)
431 {
432 if (EventListener::Del(env, handler)) {
433 LOG_INFO("Del status watch %{public}s", Anonymous::Change(sessionId_).c_str());
434 NotifierImpl::GetInstance()->DelWatcher(sessionId_);
435 return true;
436 }
437 return false;
438 }
439
Clear(napi_env env)440 void StatusEventListener::Clear(napi_env env)
441 {
442 NotifierImpl::GetInstance()->DelWatcher(sessionId_);
443 EventListener::Clear(env);
444 }
445
StatusEventListener(std::weak_ptr<JSWatcher> watcher,const std::string & sessionId)446 StatusEventListener::StatusEventListener(std::weak_ptr<JSWatcher> watcher, const std::string &sessionId)
447 : watcher_(watcher), sessionId_(sessionId)
448 {
449 }
450
Add(napi_env env,napi_value handler)451 bool ProgressEventListener::Add(napi_env env, napi_value handler)
452 {
453 LOG_INFO("Add progress watch %{public}s", Anonymous::Change(sessionId_).c_str());
454 ProgressNotifierImpl::GetInstance()->AddWatcher(sessionId_, watcher_);
455 return EventListener::Add(env, handler);
456 }
457
Del(napi_env env,napi_value handler)458 bool ProgressEventListener::Del(napi_env env, napi_value handler)
459 {
460 if (EventListener::Del(env, handler)) {
461 LOG_INFO("Del progress watch %{public}s", Anonymous::Change(sessionId_).c_str());
462 ProgressNotifierImpl::GetInstance()->DelWatcher(sessionId_);
463 return true;
464 }
465 return false;
466 }
467
Clear(napi_env env)468 void ProgressEventListener::Clear(napi_env env)
469 {
470 ProgressNotifierImpl::GetInstance()->DelWatcher(sessionId_);
471 EventListener::Clear(env);
472 }
473
ProgressEventListener(std::weak_ptr<JSWatcher> watcher,const std::string & sessionId)474 ProgressEventListener::ProgressEventListener(std::weak_ptr<JSWatcher> watcher, const std::string &sessionId)
475 : watcher_(watcher), sessionId_(sessionId)
476 {
477 }
478
ChangeArgs(const napi_ref callback,const std::string & sessionId,const std::vector<std::string> & changeData)479 JSWatcher::ChangeArgs::ChangeArgs(
480 const napi_ref callback, const std::string &sessionId, const std::vector<std::string> &changeData)
481 : callback_(callback), sessionId_(sessionId), changeData_(changeData)
482 {
483 }
484
StatusArgs(const napi_ref callback,const std::string & sessionId,const std::string & networkId,const std::string & status)485 JSWatcher::StatusArgs::StatusArgs(
486 const napi_ref callback, const std::string &sessionId, const std::string &networkId, const std::string &status)
487 : callback_(callback), sessionId_(sessionId), networkId_(networkId), status_(status)
488 {
489 }
490
ProgressArgs(const napi_ref callback,const std::string & sessionId,int32_t progress)491 JSWatcher::ProgressArgs::ProgressArgs(const napi_ref callback, const std::string &sessionId, int32_t progress)
492 : callback_(callback), sessionId_(sessionId), progress_(progress)
493 {
494 }
495 } // namespace OHOS::ObjectStore
496