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