• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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