• 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 <memory>
17 
18 #include "js_scope.h"
19 #include "js_uv_queue.h"
20 #include "logger.h"
21 namespace OHOS::AppDataMgrJsKit {
22 using namespace OHOS::Rdb;
23 constexpr size_t ARGC_MAX = 6;
UvQueue(napi_env env)24 UvQueue::UvQueue(napi_env env) : env_(env)
25 {
26     if (env != nullptr) {
27         napi_get_uv_event_loop(env, &loop_);
28     }
29     handler_ = AppExecFwk::EventHandler::Current();
30 }
31 
~UvQueue()32 UvQueue::~UvQueue()
33 {
34     LOG_DEBUG("no memory leak for queue-callback.");
35     env_ = nullptr;
36     handler_ = nullptr;
37 }
38 
AsyncCall(UvCallback callback,Args args,Result result)39 void UvQueue::AsyncCall(UvCallback callback, Args args, Result result)
40 {
41     if (loop_ == nullptr || callback.IsNull()) {
42         LOG_ERROR("loop_ or callback is nullptr.");
43         return;
44     }
45     uv_work_t *work = new (std::nothrow) uv_work_t;
46     if (work == nullptr) {
47         LOG_ERROR("no memory for uv_work_t.");
48         return;
49     }
50     auto entry = new (std::nothrow) UvEntry();
51     if (entry == nullptr) {
52         delete work;
53         LOG_ERROR("no memory for UvEntry.");
54         return;
55     }
56     entry->env_ = env_;
57     entry->object_ = callback.object_;
58     entry->callback_ = callback.callback_;
59     entry->repeat_ = callback.repeat_;
60     entry->getter_ = std::move(callback.getter_);
61     entry->args_ = std::move(args);
62     entry->result_ = std::move(result);
63     work->data = entry;
64     int ret = uv_queue_work(loop_, work, DoWork, DoUvCallback);
65     if (ret < 0) {
66         LOG_ERROR("uv_queue_work failed, errCode:%{public}d", ret);
67         delete entry;
68         delete work;
69     }
70 }
71 
AsyncCallInOrder(UvCallback callback,Args args,Result result)72 void UvQueue::AsyncCallInOrder(UvCallback callback, Args args, Result result)
73 {
74     if (handler_ == nullptr) {
75         AsyncCall(std::move(callback), std::move(args), std::move(result));
76     }
77     if (callback.IsNull()) {
78         LOG_ERROR("handler_ or callback is nullptr.");
79         return;
80     }
81     auto entry = std::make_shared<UvEntry>();
82     if (entry == nullptr) {
83         LOG_ERROR("no memory for UvEntry.");
84         return;
85     }
86     entry->env_ = env_;
87     entry->callback_ = callback.callback_;
88     entry->repeat_ = callback.repeat_;
89     entry->args_ = std::move(args);
90     if (handler_ != nullptr) {
91         handler_->PostTask(GenCallbackTask(entry));
92     }
93 }
94 
AsyncPromise(UvPromise promise,UvQueue::Args args)95 void UvQueue::AsyncPromise(UvPromise promise, UvQueue::Args args)
96 {
97     if (loop_ == nullptr || promise.IsNull()) {
98         LOG_ERROR("loop_ or promise is nullptr.");
99         return;
100     }
101     uv_work_t *work = new (std::nothrow) uv_work_t;
102     if (work == nullptr) {
103         LOG_ERROR("no memory for uv_work_t.");
104         return;
105     }
106     auto entry = new (std::nothrow) UvEntry();
107     if (entry == nullptr) {
108         delete work;
109         LOG_ERROR("no memory for UvEntry.");
110         return;
111     }
112     entry->env_ = env_;
113     entry->defer_ = promise.defer_;
114     entry->args_ = std::move(args);
115     work->data = entry;
116     int ret = uv_queue_work(loop_, work, DoWork, DoUvPromise);
117     if (ret < 0) {
118         LOG_ERROR("uv_queue_work failed, errCode:%{public}d", ret);
119         delete entry;
120         delete work;
121     }
122 }
123 
Execute(UvQueue::Task task)124 void UvQueue::Execute(UvQueue::Task task)
125 {
126     if (loop_ == nullptr || !task) {
127         LOG_ERROR("loop_ or task is nullptr.");
128         return;
129     }
130     uv_work_t *work = new (std::nothrow) uv_work_t;
131     if (work == nullptr) {
132         LOG_ERROR("no memory for uv_work_t.");
133         return;
134     }
135     auto entry = new (std::nothrow) Task();
136     if (entry == nullptr) {
137         delete work;
138         LOG_ERROR("no memory for Task.");
139         return;
140     }
141     *entry = task;
142     work->data = entry;
143     int ret = uv_queue_work(loop_, work, DoExecute, [](uv_work_t *work, int status) { delete work; });
144     if (ret < 0) {
145         LOG_ERROR("uv_queue_work failed, errCode:%{public}d", ret);
146         delete entry;
147         delete work;
148     }
149 }
150 
GetEnv()151 napi_env UvQueue::GetEnv()
152 {
153     return env_;
154 }
155 
Resolved(napi_env env,napi_callback_info info)156 napi_value UvQueue::Resolved(napi_env env, napi_callback_info info)
157 {
158     return Future(env, info, false);
159 }
160 
Rejected(napi_env env,napi_callback_info info)161 napi_value UvQueue::Rejected(napi_env env, napi_callback_info info)
162 {
163     return Future(env, info, true);
164 }
165 
Future(napi_env env,napi_callback_info info,bool exception)166 napi_value UvQueue::Future(napi_env env, napi_callback_info info, bool exception)
167 {
168     size_t argc = ARGC_MAX;
169     napi_value argv[ARGC_MAX] = { nullptr };
170     void *data = nullptr;
171     auto status = napi_get_cb_info(env, info, &argc, argv, nullptr, &data);
172     if (status != napi_ok) {
173         return nullptr;
174     }
175     auto *entry = static_cast<Result *>(data);
176     if (entry) {
177         (*entry)(env, argc, argv, exception);
178         delete entry;
179     }
180     return nullptr;
181 }
182 
DoWork(uv_work_t * work)183 void UvQueue::DoWork(uv_work_t *work)
184 {
185 }
186 
DoExecute(uv_work_t * work)187 void UvQueue::DoExecute(uv_work_t *work)
188 {
189     Task *task = static_cast<Task *>(work->data);
190     work->data = nullptr;
191     (*task)();
192     delete task;
193 }
194 
DoUvCallback(uv_work_t * work,int status)195 void UvQueue::DoUvCallback(uv_work_t *work, int status)
196 {
197     std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
198         delete data;
199         delete work;
200     });
201 
202     GenCallbackTask(entry)();
203 }
204 
GenCallbackTask(std::shared_ptr<UvEntry> entry)205 UvQueue::Task UvQueue::GenCallbackTask(std::shared_ptr<UvEntry> entry)
206 {
207     return [entry]() {
208         if (entry == nullptr) {
209             return;
210         }
211         Scope scope(entry->env_);
212         napi_value method = entry->GetCallback();
213         if (method == nullptr) {
214             entry->DelReference();
215             LOG_ERROR("the callback is invalid, maybe is cleared!");
216             return;
217         }
218         napi_value argv[ARGC_MAX] = { nullptr };
219         auto argc = entry->GetArgv(argv, ARGC_MAX);
220         auto object = entry->GetObject();
221         napi_value promise = nullptr;
222         auto status = napi_call_function(entry->env_, object, method, argc, argv, &promise);
223         entry->DelReference();
224         if (status != napi_ok) {
225             LOG_ERROR("notify data change failed status:%{public}d.", status);
226             return;
227         }
228         entry->BindPromise(promise);
229     };
230 }
231 
DoUvPromise(uv_work_t * work,int status)232 void UvQueue::DoUvPromise(uv_work_t *work, int status)
233 {
234     std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
235         delete data;
236         delete work;
237     });
238 
239     Scope scope(entry->env_);
240 
241     napi_value argv[ARG_BUTT] = { nullptr };
242     auto argc = entry->GetArgv(argv, ARG_BUTT);
243     if (argv[ARG_ERROR] != nullptr || argc != ARG_BUTT) {
244         napi_reject_deferred(entry->env_, entry->defer_, argv[ARG_ERROR]);
245     } else {
246         napi_resolve_deferred(entry->env_, entry->defer_, argv[ARG_DATA]);
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     napi_call_function(env_, promise, then, 2, argv, &result);
323 }
324 
StealResult()325 UvQueue::Result *UvQueue::UvEntry::StealResult()
326 {
327     if (!result_) {
328         return nullptr;
329     }
330     auto *result = new Result();
331     *result = std::move(result_);
332     return result;
333 }
334 } // namespace OHOS::AppDataMgrJsKit
335