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
16 #include "napi_queue.h"
17 namespace OHOS::CalendarApi {
~ContextBase()18 ContextBase::~ContextBase()
19 {
20 LOG_DEBUG("no memory leak after callback or promise[resolved/rejected]");
21 if (env != nullptr) {
22 if (callbackRef != nullptr) {
23 auto status = napi_delete_reference(env, callbackRef);
24 LOG_DEBUG("status:%{public}d", status);
25 }
26 if (selfRef != nullptr) {
27 auto status = napi_delete_reference(env, selfRef);
28 LOG_DEBUG("status:%{public}d", status);
29 }
30 env = nullptr;
31 }
32 }
33
GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parse, bool sync)34 void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parse, bool sync)
35 {
36 env = envi;
37 size_t argc = ARGC_MAX;
38 napi_value argv[ARGC_MAX] = { nullptr };
39 status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr);
40 CHECK_STATUS_RETURN_VOID(this, " napi_get_cb_info failed!");
41 CHECK_ARGS_RETURN_VOID(this, argc <= ARGC_MAX, " too many arguments!");
42 CHECK_ARGS_RETURN_VOID(this, self != nullptr, " no JavaScript this argument!");
43 if (!sync) {
44 napi_create_reference(env, self, 1, &selfRef);
45 }
46 status = napi_unwrap(env, self, &native);
47 CHECK_STATUS_RETURN_VOID(this, " self unwrap failed!");
48
49 if (!sync && (argc > 0)) {
50 // get the last arguments :: <callback>
51 size_t index = argc - 1;
52 napi_valuetype type = napi_undefined;
53 napi_status tyst = napi_typeof(env, argv[index], &type);
54 if ((tyst == napi_ok) && (type == napi_function)) {
55 status = napi_create_reference(env, argv[index], 1, &callbackRef);
56 CHECK_STATUS_RETURN_VOID(this, " ref callback failed!");
57 argc = index;
58 LOG_DEBUG(" async callback, no promise");
59 } else {
60 LOG_DEBUG(" no callback, async pormose");
61 }
62 }
63
64 if (parse) {
65 parse(argc, argv);
66 } else {
67 CHECK_ARGS_RETURN_VOID(this, argc == 0, " required no arguments!");
68 }
69 }
70
AsyncWork(napi_env env, std::shared_ptr<ContextBase> ctxt, const std::string& name, NapiAsyncExecute execute, NapiAsyncComplete complete)71 napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr<ContextBase> ctxt, const std::string& name,
72 NapiAsyncExecute execute, NapiAsyncComplete complete)
73 {
74 LOG_DEBUG("name = %{public}s", name.c_str());
75 AsyncContext *aCtx = new AsyncContext;
76 aCtx->env = env;
77 aCtx->ctx = std::move(ctxt);
78 aCtx->execute = std::move(execute);
79 aCtx->complete = std::move(complete);
80 napi_value promise = nullptr;
81 if (aCtx->ctx->callbackRef == nullptr) {
82 napi_create_promise(env, &aCtx->deferred, &promise);
83 LOG_DEBUG("AsyncWork create deferred promise");
84 } else {
85 napi_get_undefined(env, &promise);
86 }
87
88 napi_value resource = nullptr;
89 napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource);
90 napi_create_async_work(
91 env, nullptr, resource,
92 [](napi_env env, void* data) {
93 CHECK_RETURN_VOID(data != nullptr, "AsyncWork napi_async_execute_callback nullptr");
94 auto actx = reinterpret_cast<AsyncContext*>(data);
95 LOG_DEBUG("AsyncWork napi_async_execute_callback ctxt->status=%{public}d", actx->ctx->status);
96 if (actx->execute && actx->ctx->status == napi_ok) {
97 actx->execute();
98 }
99 },
100 [](napi_env env, napi_status status, void* data) {
101 CHECK_RETURN_VOID(data != nullptr, "AsyncWork napi_async_complete_callback nullptr");
102 auto actx = reinterpret_cast<AsyncContext*>(data);
103 LOG_DEBUG("AsyncWork napi_async_complete_callback status = %{public}d, ctxt->status = %{public}d",
104 status, actx->ctx->status);
105 if ((status != napi_ok) && (actx->ctx->status == napi_ok)) {
106 actx->ctx->status = status;
107 }
108 napi_value output = nullptr;
109 if ((actx->complete) && (status == napi_ok) && (actx->ctx->status == napi_ok)) {
110 actx->complete(output);
111 }
112 GenerateOutput(*actx, output);
113 delete actx;
114 },
115 reinterpret_cast<void*>(aCtx), &aCtx->work);
116 auto status = napi_queue_async_work(env, aCtx->work);
117 if (status != napi_ok) {
118 napi_get_undefined(env, &promise);
119 delete aCtx;
120 }
121 return promise;
122 }
123
GenerateOutput(AsyncContext &ctx, napi_value output)124 void NapiQueue::GenerateOutput(AsyncContext &ctx, napi_value output)
125 {
126 napi_value result[RESULT_ALL] = { nullptr };
127 if (ctx.ctx->status == napi_ok) {
128 napi_get_undefined(ctx.env, &result[RESULT_ERROR]);
129 if (output == nullptr) {
130 napi_get_undefined(ctx.env, &output);
131 }
132 result[RESULT_DATA] = output;
133 } else {
134 napi_value message = nullptr;
135 napi_create_string_utf8(ctx.env, ctx.ctx->error.c_str(), NAPI_AUTO_LENGTH, &message);
136 napi_create_error(ctx.env, nullptr, message, &result[RESULT_ERROR]);
137 napi_get_undefined(ctx.env, &result[RESULT_DATA]);
138 }
139 if (ctx.deferred != nullptr) {
140 if (ctx.ctx->status == napi_ok) {
141 LOG_DEBUG("GenerateOutput deferred promise resolved");
142 napi_resolve_deferred(ctx.env, ctx.deferred, result[RESULT_DATA]);
143 } else {
144 LOG_DEBUG("GenerateOutput deferred promise rejected");
145 napi_reject_deferred(ctx.env, ctx.deferred, result[RESULT_ERROR]);
146 }
147 } else {
148 napi_value callback = nullptr;
149 napi_get_reference_value(ctx.env, ctx.ctx->callbackRef, &callback);
150 napi_value callbackResult = nullptr;
151 LOG_DEBUG("GenerateOutput call callback function");
152 napi_call_function(ctx.env, nullptr, callback, RESULT_ALL, result, &callbackResult);
153 }
154 }
155 } // namespace OHOS::Calendar