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