10fbfc30aSopenharmony_ci/*
20fbfc30aSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
30fbfc30aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
40fbfc30aSopenharmony_ci * you may not use this file except in compliance with the License.
50fbfc30aSopenharmony_ci * You may obtain a copy of the License at
60fbfc30aSopenharmony_ci *
70fbfc30aSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
80fbfc30aSopenharmony_ci *
90fbfc30aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
100fbfc30aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
110fbfc30aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120fbfc30aSopenharmony_ci * See the License for the specific language governing permissions and
130fbfc30aSopenharmony_ci * limitations under the License.
140fbfc30aSopenharmony_ci */
150fbfc30aSopenharmony_ci
160fbfc30aSopenharmony_ci#include "napi_queue.h"
170fbfc30aSopenharmony_cinamespace OHOS::CalendarApi {
180fbfc30aSopenharmony_ciContextBase::~ContextBase()
190fbfc30aSopenharmony_ci{
200fbfc30aSopenharmony_ci    LOG_DEBUG("no memory leak after callback or promise[resolved/rejected]");
210fbfc30aSopenharmony_ci    if (env != nullptr) {
220fbfc30aSopenharmony_ci        if (callbackRef != nullptr) {
230fbfc30aSopenharmony_ci            auto status = napi_delete_reference(env, callbackRef);
240fbfc30aSopenharmony_ci            LOG_DEBUG("status:%{public}d", status);
250fbfc30aSopenharmony_ci        }
260fbfc30aSopenharmony_ci        if (selfRef != nullptr) {
270fbfc30aSopenharmony_ci            auto status = napi_delete_reference(env, selfRef);
280fbfc30aSopenharmony_ci            LOG_DEBUG("status:%{public}d", status);
290fbfc30aSopenharmony_ci        }
300fbfc30aSopenharmony_ci        env = nullptr;
310fbfc30aSopenharmony_ci    }
320fbfc30aSopenharmony_ci}
330fbfc30aSopenharmony_ci
340fbfc30aSopenharmony_civoid ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parse, bool sync)
350fbfc30aSopenharmony_ci{
360fbfc30aSopenharmony_ci    env = envi;
370fbfc30aSopenharmony_ci    size_t argc = ARGC_MAX;
380fbfc30aSopenharmony_ci    napi_value argv[ARGC_MAX] = { nullptr };
390fbfc30aSopenharmony_ci    status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr);
400fbfc30aSopenharmony_ci    CHECK_STATUS_RETURN_VOID(this, " napi_get_cb_info failed!");
410fbfc30aSopenharmony_ci    CHECK_ARGS_RETURN_VOID(this, argc <= ARGC_MAX, " too many arguments!");
420fbfc30aSopenharmony_ci    CHECK_ARGS_RETURN_VOID(this, self != nullptr, " no JavaScript this argument!");
430fbfc30aSopenharmony_ci    if (!sync) {
440fbfc30aSopenharmony_ci        napi_create_reference(env, self, 1, &selfRef);
450fbfc30aSopenharmony_ci    }
460fbfc30aSopenharmony_ci    status = napi_unwrap(env, self, &native);
470fbfc30aSopenharmony_ci    CHECK_STATUS_RETURN_VOID(this, " self unwrap failed!");
480fbfc30aSopenharmony_ci
490fbfc30aSopenharmony_ci    if (!sync && (argc > 0)) {
500fbfc30aSopenharmony_ci        // get the last arguments :: <callback>
510fbfc30aSopenharmony_ci        size_t index = argc - 1;
520fbfc30aSopenharmony_ci        napi_valuetype type = napi_undefined;
530fbfc30aSopenharmony_ci        napi_status tyst = napi_typeof(env, argv[index], &type);
540fbfc30aSopenharmony_ci        if ((tyst == napi_ok) && (type == napi_function)) {
550fbfc30aSopenharmony_ci            status = napi_create_reference(env, argv[index], 1, &callbackRef);
560fbfc30aSopenharmony_ci            CHECK_STATUS_RETURN_VOID(this, " ref callback failed!");
570fbfc30aSopenharmony_ci            argc = index;
580fbfc30aSopenharmony_ci            LOG_DEBUG(" async callback, no promise");
590fbfc30aSopenharmony_ci        } else {
600fbfc30aSopenharmony_ci            LOG_DEBUG(" no callback, async pormose");
610fbfc30aSopenharmony_ci        }
620fbfc30aSopenharmony_ci    }
630fbfc30aSopenharmony_ci
640fbfc30aSopenharmony_ci    if (parse) {
650fbfc30aSopenharmony_ci        parse(argc, argv);
660fbfc30aSopenharmony_ci    } else {
670fbfc30aSopenharmony_ci        CHECK_ARGS_RETURN_VOID(this, argc == 0, " required no arguments!");
680fbfc30aSopenharmony_ci    }
690fbfc30aSopenharmony_ci}
700fbfc30aSopenharmony_ci
710fbfc30aSopenharmony_cinapi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr<ContextBase> ctxt, const std::string& name,
720fbfc30aSopenharmony_ci                                NapiAsyncExecute execute, NapiAsyncComplete complete)
730fbfc30aSopenharmony_ci{
740fbfc30aSopenharmony_ci    LOG_DEBUG("name = %{public}s", name.c_str());
750fbfc30aSopenharmony_ci    AsyncContext *aCtx = new AsyncContext;
760fbfc30aSopenharmony_ci    aCtx->env = env;
770fbfc30aSopenharmony_ci    aCtx->ctx = std::move(ctxt);
780fbfc30aSopenharmony_ci    aCtx->execute = std::move(execute);
790fbfc30aSopenharmony_ci    aCtx->complete = std::move(complete);
800fbfc30aSopenharmony_ci    napi_value promise = nullptr;
810fbfc30aSopenharmony_ci    if (aCtx->ctx->callbackRef == nullptr) {
820fbfc30aSopenharmony_ci        napi_create_promise(env, &aCtx->deferred, &promise);
830fbfc30aSopenharmony_ci        LOG_DEBUG("AsyncWork create deferred promise");
840fbfc30aSopenharmony_ci    } else {
850fbfc30aSopenharmony_ci        napi_get_undefined(env, &promise);
860fbfc30aSopenharmony_ci    }
870fbfc30aSopenharmony_ci
880fbfc30aSopenharmony_ci    napi_value resource = nullptr;
890fbfc30aSopenharmony_ci    napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource);
900fbfc30aSopenharmony_ci    napi_create_async_work(
910fbfc30aSopenharmony_ci        env, nullptr, resource,
920fbfc30aSopenharmony_ci        [](napi_env env, void* data) {
930fbfc30aSopenharmony_ci            CHECK_RETURN_VOID(data != nullptr, "AsyncWork napi_async_execute_callback nullptr");
940fbfc30aSopenharmony_ci            auto actx = reinterpret_cast<AsyncContext*>(data);
950fbfc30aSopenharmony_ci            LOG_DEBUG("AsyncWork napi_async_execute_callback ctxt->status=%{public}d", actx->ctx->status);
960fbfc30aSopenharmony_ci            if (actx->execute && actx->ctx->status == napi_ok) {
970fbfc30aSopenharmony_ci                actx->execute();
980fbfc30aSopenharmony_ci            }
990fbfc30aSopenharmony_ci        },
1000fbfc30aSopenharmony_ci        [](napi_env env, napi_status status, void* data) {
1010fbfc30aSopenharmony_ci            CHECK_RETURN_VOID(data != nullptr, "AsyncWork napi_async_complete_callback nullptr");
1020fbfc30aSopenharmony_ci            auto actx = reinterpret_cast<AsyncContext*>(data);
1030fbfc30aSopenharmony_ci            LOG_DEBUG("AsyncWork napi_async_complete_callback status = %{public}d, ctxt->status = %{public}d",
1040fbfc30aSopenharmony_ci                status, actx->ctx->status);
1050fbfc30aSopenharmony_ci            if ((status != napi_ok) && (actx->ctx->status == napi_ok)) {
1060fbfc30aSopenharmony_ci                actx->ctx->status = status;
1070fbfc30aSopenharmony_ci            }
1080fbfc30aSopenharmony_ci            napi_value output = nullptr;
1090fbfc30aSopenharmony_ci            if ((actx->complete) && (status == napi_ok) && (actx->ctx->status == napi_ok)) {
1100fbfc30aSopenharmony_ci                actx->complete(output);
1110fbfc30aSopenharmony_ci            }
1120fbfc30aSopenharmony_ci            GenerateOutput(*actx, output);
1130fbfc30aSopenharmony_ci            delete actx;
1140fbfc30aSopenharmony_ci        },
1150fbfc30aSopenharmony_ci        reinterpret_cast<void*>(aCtx), &aCtx->work);
1160fbfc30aSopenharmony_ci    auto status = napi_queue_async_work(env, aCtx->work);
1170fbfc30aSopenharmony_ci    if (status != napi_ok) {
1180fbfc30aSopenharmony_ci        napi_get_undefined(env, &promise);
1190fbfc30aSopenharmony_ci        delete aCtx;
1200fbfc30aSopenharmony_ci    }
1210fbfc30aSopenharmony_ci    return promise;
1220fbfc30aSopenharmony_ci}
1230fbfc30aSopenharmony_ci
1240fbfc30aSopenharmony_civoid NapiQueue::GenerateOutput(AsyncContext &ctx, napi_value output)
1250fbfc30aSopenharmony_ci{
1260fbfc30aSopenharmony_ci    napi_value result[RESULT_ALL] = { nullptr };
1270fbfc30aSopenharmony_ci    if (ctx.ctx->status == napi_ok) {
1280fbfc30aSopenharmony_ci        napi_get_undefined(ctx.env, &result[RESULT_ERROR]);
1290fbfc30aSopenharmony_ci        if (output == nullptr) {
1300fbfc30aSopenharmony_ci            napi_get_undefined(ctx.env, &output);
1310fbfc30aSopenharmony_ci        }
1320fbfc30aSopenharmony_ci        result[RESULT_DATA] = output;
1330fbfc30aSopenharmony_ci    } else {
1340fbfc30aSopenharmony_ci        napi_value message = nullptr;
1350fbfc30aSopenharmony_ci        napi_create_string_utf8(ctx.env, ctx.ctx->error.c_str(), NAPI_AUTO_LENGTH, &message);
1360fbfc30aSopenharmony_ci        napi_create_error(ctx.env, nullptr, message, &result[RESULT_ERROR]);
1370fbfc30aSopenharmony_ci        napi_get_undefined(ctx.env, &result[RESULT_DATA]);
1380fbfc30aSopenharmony_ci    }
1390fbfc30aSopenharmony_ci    if (ctx.deferred != nullptr) {
1400fbfc30aSopenharmony_ci        if (ctx.ctx->status == napi_ok) {
1410fbfc30aSopenharmony_ci            LOG_DEBUG("GenerateOutput deferred promise resolved");
1420fbfc30aSopenharmony_ci            napi_resolve_deferred(ctx.env, ctx.deferred, result[RESULT_DATA]);
1430fbfc30aSopenharmony_ci        } else {
1440fbfc30aSopenharmony_ci            LOG_DEBUG("GenerateOutput deferred promise rejected");
1450fbfc30aSopenharmony_ci            napi_reject_deferred(ctx.env, ctx.deferred, result[RESULT_ERROR]);
1460fbfc30aSopenharmony_ci        }
1470fbfc30aSopenharmony_ci    } else {
1480fbfc30aSopenharmony_ci        napi_value callback = nullptr;
1490fbfc30aSopenharmony_ci        napi_get_reference_value(ctx.env, ctx.ctx->callbackRef, &callback);
1500fbfc30aSopenharmony_ci        napi_value callbackResult = nullptr;
1510fbfc30aSopenharmony_ci        LOG_DEBUG("GenerateOutput call callback function");
1520fbfc30aSopenharmony_ci        napi_call_function(ctx.env, nullptr, callback, RESULT_ALL, result, &callbackResult);
1530fbfc30aSopenharmony_ci    }
1540fbfc30aSopenharmony_ci}
1550fbfc30aSopenharmony_ci} // namespace OHOS::Calendar