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