• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #define LOG_TAG "UvQueue"
16 #include "js_uv_queue.h"
17 
18 #include <memory>
19 
20 #include "js_scope.h"
21 #include "logger.h"
22 namespace OHOS::AppDataMgrJsKit {
23 using namespace OHOS::Rdb;
24 constexpr size_t ARGC_MAX = 6;
UvQueue(napi_env env)25 UvQueue::UvQueue(napi_env env) : env_(env)
26 {
27     if (env != nullptr) {
28         napi_get_uv_event_loop(env, &loop_);
29     }
30     handler_ = AppExecFwk::EventHandler::Current();
31 }
32 
~UvQueue()33 UvQueue::~UvQueue()
34 {
35     LOG_DEBUG("No memory leak for queue-callback.");
36     env_ = nullptr;
37     handler_ = nullptr;
38 }
39 
AsyncCall(UvCallback callback,Args args,Result result)40 void UvQueue::AsyncCall(UvCallback callback, Args args, Result result)
41 {
42     if (loop_ == nullptr || callback.IsNull()) {
43         LOG_ERROR("loop_ or callback is nullptr.");
44         return;
45     }
46     uv_work_t *work = new (std::nothrow) uv_work_t;
47     if (work == nullptr) {
48         LOG_ERROR("No memory for uv_work_t.");
49         return;
50     }
51     auto entry = new (std::nothrow) UvEntry();
52     if (entry == nullptr) {
53         delete work;
54         LOG_ERROR("No memory for UvEntry.");
55         return;
56     }
57     entry->env_ = env_;
58     entry->object_ = callback.object_;
59     entry->callback_ = callback.callback_;
60     entry->repeat_ = callback.repeat_;
61     entry->getter_ = std::move(callback.getter_);
62     entry->args_ = std::move(args);
63     entry->result_ = std::move(result);
64     work->data = entry;
65     int ret = uv_queue_work(loop_, work, DoWork, DoUvCallback);
66     if (ret < 0) {
67         LOG_ERROR("uv_queue_work failed, errCode:%{public}d", ret);
68         delete entry;
69         delete work;
70     }
71 }
72 
AsyncCallInOrder(UvCallback callback,Args args,Result result)73 void UvQueue::AsyncCallInOrder(UvCallback callback, Args args, Result result)
74 {
75     if (handler_ == nullptr) {
76         AsyncCall(std::move(callback), std::move(args), std::move(result));
77     }
78     if (callback.IsNull()) {
79         LOG_ERROR("handler_ or callback is nullptr.");
80         return;
81     }
82     auto entry = std::make_shared<UvEntry>();
83     if (entry == nullptr) {
84         LOG_ERROR("No memory for UvEntry.");
85         return;
86     }
87     entry->env_ = env_;
88     entry->callback_ = callback.callback_;
89     entry->repeat_ = callback.repeat_;
90     entry->args_ = std::move(args);
91     if (handler_ != nullptr) {
92         handler_->PostTask(GenCallbackTask(entry));
93     }
94 }
95 
AsyncPromise(UvPromise promise,UvQueue::Args args)96 void UvQueue::AsyncPromise(UvPromise promise, UvQueue::Args args)
97 {
98     if (loop_ == nullptr || promise.IsNull()) {
99         LOG_ERROR("loop_ or promise is nullptr.");
100         return;
101     }
102     uv_work_t *work = new (std::nothrow) uv_work_t;
103     if (work == nullptr) {
104         LOG_ERROR("No memory for uv_work_t.");
105         return;
106     }
107     auto entry = new (std::nothrow) UvEntry();
108     if (entry == nullptr) {
109         delete work;
110         LOG_ERROR("No memory for UvEntry.");
111         return;
112     }
113     entry->env_ = env_;
114     entry->defer_ = promise.defer_;
115     entry->args_ = std::move(args);
116     work->data = entry;
117     int ret = uv_queue_work(loop_, work, DoWork, DoUvPromise);
118     if (ret < 0) {
119         LOG_ERROR("uv_queue_work failed, errCode:%{public}d", ret);
120         delete entry;
121         delete work;
122     }
123 }
124 
Execute(UvQueue::Task task)125 void UvQueue::Execute(UvQueue::Task task)
126 {
127     if (loop_ == nullptr || !task) {
128         LOG_ERROR("loop_ or task is nullptr.");
129         return;
130     }
131     uv_work_t *work = new (std::nothrow) uv_work_t;
132     if (work == nullptr) {
133         LOG_ERROR("No memory for uv_work_t.");
134         return;
135     }
136     auto entry = new (std::nothrow) Task();
137     if (entry == nullptr) {
138         delete work;
139         LOG_ERROR("No memory for Task.");
140         return;
141     }
142     *entry = task;
143     work->data = entry;
144     int ret = uv_queue_work(loop_, work, DoExecute, [](uv_work_t *work, int status) { delete work; });
145     if (ret < 0) {
146         LOG_ERROR("uv_queue_work failed, errCode:%{public}d", ret);
147         delete entry;
148         delete work;
149     }
150 }
151 
GetEnv()152 napi_env UvQueue::GetEnv()
153 {
154     return env_;
155 }
156 
Resolved(napi_env env,napi_callback_info info)157 napi_value UvQueue::Resolved(napi_env env, napi_callback_info info)
158 {
159     return Future(env, info, false);
160 }
161 
Rejected(napi_env env,napi_callback_info info)162 napi_value UvQueue::Rejected(napi_env env, napi_callback_info info)
163 {
164     return Future(env, info, true);
165 }
166 
Future(napi_env env,napi_callback_info info,bool exception)167 napi_value UvQueue::Future(napi_env env, napi_callback_info info, bool exception)
168 {
169     size_t argc = ARGC_MAX;
170     napi_value argv[ARGC_MAX] = { nullptr };
171     void *data = nullptr;
172     auto status = napi_get_cb_info(env, info, &argc, argv, nullptr, &data);
173     if (status != napi_ok) {
174         return nullptr;
175     }
176     auto *entry = static_cast<Result *>(data);
177     if (entry) {
178         (*entry)(env, argc, argv, exception);
179         delete entry;
180     }
181     return nullptr;
182 }
183 
DoWork(uv_work_t * work)184 void UvQueue::DoWork(uv_work_t *work)
185 {
186 }
187 
DoExecute(uv_work_t * work)188 void UvQueue::DoExecute(uv_work_t *work)
189 {
190     Task *task = static_cast<Task *>(work->data);
191     work->data = nullptr;
192     (*task)();
193     delete task;
194 }
195 
DoUvCallback(uv_work_t * work,int status)196 void UvQueue::DoUvCallback(uv_work_t *work, int status)
197 {
198     std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
199         delete data;
200         delete work;
201     });
202 
203     GenCallbackTask(entry)();
204 }
205 
DoUvPromise(uv_work_t * work,int status)206 void UvQueue::DoUvPromise(uv_work_t *work, int status)
207 {
208     std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
209         delete data;
210         delete work;
211     });
212 
213     Scope scope(entry->env_);
214     napi_value argv[ARG_BUTT] = { nullptr };
215     auto argc = entry->GetArgv(argv, ARG_BUTT);
216     if (argv[ARG_ERROR] != nullptr || argc != ARG_BUTT) {
217         napi_reject_deferred(entry->env_, entry->defer_, argv[ARG_ERROR]);
218     } else {
219         napi_resolve_deferred(entry->env_, entry->defer_, argv[ARG_DATA]);
220     }
221 }
222 
GenCallbackTask(std::shared_ptr<UvEntry> entry)223 UvQueue::Task UvQueue::GenCallbackTask(std::shared_ptr<UvEntry> entry)
224 {
225     return [entry]() {
226         if (entry == nullptr) {
227             return;
228         }
229         Scope scope(entry->env_);
230         napi_value method = entry->GetCallback();
231         if (method == nullptr) {
232             entry->DelReference();
233             LOG_ERROR("The callback is invalid, maybe is cleared!");
234             return;
235         }
236         napi_value argv[ARGC_MAX] = { nullptr };
237         auto argc = entry->GetArgv(argv, ARGC_MAX);
238         auto object = entry->GetObject();
239         napi_value promise = nullptr;
240         auto status = napi_call_function(entry->env_, object, method, argc, argv, &promise);
241         entry->DelReference();
242         if (status != napi_ok) {
243             LOG_ERROR("Notify data change failed status:%{public}d.", status);
244             return;
245         }
246         entry->BindPromise(promise);
247     };
248 }
249 
~UvEntry()250 UvQueue::UvEntry::~UvEntry()
251 {
252 }
253 
DelReference()254 void UvQueue::UvEntry::DelReference()
255 {
256     if (callback_ != nullptr && !repeat_) {
257         napi_delete_reference(env_, callback_);
258         callback_ = nullptr;
259     }
260     if (object_ != nullptr) {
261         napi_delete_reference(env_, object_);
262         object_ = nullptr;
263     }
264 }
265 
GetCallback()266 napi_value UvQueue::UvEntry::GetCallback()
267 {
268     napi_value method = nullptr;
269     if (callback_ != nullptr) {
270         napi_get_reference_value(env_, callback_, &method);
271     } else if (getter_) {
272         method = getter_(env_);
273     }
274     return method;
275 }
276 
GetArgv(napi_value * argv,int32_t max)277 int32_t UvQueue::UvEntry::GetArgv(napi_value *argv, int32_t max)
278 {
279     int32_t argc = 0;
280     if (args_) {
281         argc = max;
282         args_(env_, argc, argv);
283     }
284     return argc;
285 }
286 
GetObject()287 napi_value UvQueue::UvEntry::GetObject()
288 {
289     napi_value object = nullptr;
290     if (object_ == nullptr) {
291         napi_get_global(env_, &object);
292     } else {
293         napi_get_reference_value(env_, object_, &object);
294     }
295     return object;
296 }
297 
BindPromise(napi_value promise)298 void UvQueue::UvEntry::BindPromise(napi_value promise)
299 {
300     if (promise == nullptr || !result_) {
301         return;
302     }
303 
304     bool isPromise = false;
305     auto status = napi_is_promise(env_, promise, &isPromise);
306     if (status != napi_ok || !isPromise) {
307         result_(env_, 1, &promise, false);
308         return;
309     }
310 
311     napi_value then = nullptr;
312     if (napi_get_named_property(env_, promise, "then", &then) != napi_ok || then == nullptr) {
313         return;
314     }
315 
316     auto object = StealResult();
317     napi_value argv[ARGC_MAX] = { nullptr };
318     napi_create_function(env_, RESOLVED, RESOLVED_SIZE, Resolved, object, &argv[0]);
319     napi_create_function(env_, REJECTED, REJECTED_SIZE, Rejected, object, &argv[1]);
320     napi_value result = nullptr;
321     // Enter 2 parameters argv[0] and argv[1]
322     status = napi_call_function(env_, promise, then, 2, argv, &result);
323     if (status != napi_ok && object != nullptr) {
324         delete object;
325     }
326 }
327 
StealResult()328 UvQueue::Result *UvQueue::UvEntry::StealResult()
329 {
330     if (!result_) {
331         return nullptr;
332     }
333     auto *result = new Result();
334     *result = std::move(result_);
335     return result;
336 }
337 } // namespace OHOS::AppDataMgrJsKit
338