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