1bc03f14fSopenharmony_ci/*
2bc03f14fSopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3bc03f14fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4bc03f14fSopenharmony_ci * you may not use this file except in compliance with the License.
5bc03f14fSopenharmony_ci * You may obtain a copy of the License at
6bc03f14fSopenharmony_ci *
7bc03f14fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8bc03f14fSopenharmony_ci *
9bc03f14fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10bc03f14fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11bc03f14fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12bc03f14fSopenharmony_ci * See the License for the specific language governing permissions and
13bc03f14fSopenharmony_ci * limitations under the License.
14bc03f14fSopenharmony_ci */
15bc03f14fSopenharmony_ci#define LOG_TAG "PasteBoardAsyncCall"
16bc03f14fSopenharmony_ci#include "async_call.h"
17bc03f14fSopenharmony_ci#include "pasteboard_hilog.h"
18bc03f14fSopenharmony_ci
19bc03f14fSopenharmony_ciusing namespace OHOS::MiscServices;
20bc03f14fSopenharmony_ci
21bc03f14fSopenharmony_cinamespace OHOS::MiscServicesNapi {
22bc03f14fSopenharmony_ciAsyncCall::AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr<Context> context, size_t pos) : env_(env)
23bc03f14fSopenharmony_ci{
24bc03f14fSopenharmony_ci    context_ = new AsyncContext();
25bc03f14fSopenharmony_ci    size_t argc = 6;
26bc03f14fSopenharmony_ci    napi_value self = nullptr;
27bc03f14fSopenharmony_ci    napi_value argv[6] = { nullptr };
28bc03f14fSopenharmony_ci    NAPI_CALL_RETURN_VOID(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
29bc03f14fSopenharmony_ci    pos = ((pos == ASYNC_DEFAULT_POS) ? (argc - 1) : pos);
30bc03f14fSopenharmony_ci    if (pos >= 0 && pos < argc) {
31bc03f14fSopenharmony_ci        napi_valuetype valueType = napi_undefined;
32bc03f14fSopenharmony_ci        napi_typeof(env, argv[pos], &valueType);
33bc03f14fSopenharmony_ci        if (valueType == napi_function) {
34bc03f14fSopenharmony_ci            napi_create_reference(env, argv[pos], 1, &context_->callback);
35bc03f14fSopenharmony_ci        }
36bc03f14fSopenharmony_ci    }
37bc03f14fSopenharmony_ci    napi_status status = (*context)(env, argc, argv, self);
38bc03f14fSopenharmony_ci    if (status != napi_ok) {
39bc03f14fSopenharmony_ci        return;
40bc03f14fSopenharmony_ci    }
41bc03f14fSopenharmony_ci    context_->ctx = std::move(context);
42bc03f14fSopenharmony_ci    napi_create_reference(env, self, 1, &context_->self);
43bc03f14fSopenharmony_ci}
44bc03f14fSopenharmony_ci
45bc03f14fSopenharmony_ciAsyncCall::~AsyncCall()
46bc03f14fSopenharmony_ci{
47bc03f14fSopenharmony_ci    if (context_ == nullptr) {
48bc03f14fSopenharmony_ci        return;
49bc03f14fSopenharmony_ci    }
50bc03f14fSopenharmony_ci
51bc03f14fSopenharmony_ci    DeleteContext(env_, context_);
52bc03f14fSopenharmony_ci}
53bc03f14fSopenharmony_ci
54bc03f14fSopenharmony_cinapi_value AsyncCall::Call(napi_env env, Context::ExecAction exec)
55bc03f14fSopenharmony_ci{
56bc03f14fSopenharmony_ci    if (context_ == nullptr) {
57bc03f14fSopenharmony_ci        PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "context_ is null");
58bc03f14fSopenharmony_ci        return nullptr;
59bc03f14fSopenharmony_ci    }
60bc03f14fSopenharmony_ci    if (context_->ctx == nullptr) {
61bc03f14fSopenharmony_ci        PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "context_->ctx is null");
62bc03f14fSopenharmony_ci        return nullptr;
63bc03f14fSopenharmony_ci    }
64bc03f14fSopenharmony_ci
65bc03f14fSopenharmony_ci    context_->ctx->exec_ = std::move(exec);
66bc03f14fSopenharmony_ci    napi_value promise = nullptr;
67bc03f14fSopenharmony_ci    if (context_->callback == nullptr) {
68bc03f14fSopenharmony_ci        napi_create_promise(env, &context_->defer, &promise);
69bc03f14fSopenharmony_ci    } else {
70bc03f14fSopenharmony_ci        napi_get_undefined(env, &promise);
71bc03f14fSopenharmony_ci    }
72bc03f14fSopenharmony_ci    napi_async_work work = context_->work;
73bc03f14fSopenharmony_ci    napi_value resource = nullptr;
74bc03f14fSopenharmony_ci    napi_create_string_utf8(env, LOG_TAG, NAPI_AUTO_LENGTH, &resource);
75bc03f14fSopenharmony_ci    napi_create_async_work(env, nullptr, resource, AsyncCall::OnExecute, AsyncCall::OnComplete, context_, &work);
76bc03f14fSopenharmony_ci    context_->work = work;
77bc03f14fSopenharmony_ci    context_ = nullptr;
78bc03f14fSopenharmony_ci    napi_queue_async_work_with_qos(env, work, napi_qos_user_initiated);
79bc03f14fSopenharmony_ci    PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "async call exec");
80bc03f14fSopenharmony_ci    return promise;
81bc03f14fSopenharmony_ci}
82bc03f14fSopenharmony_ci
83bc03f14fSopenharmony_cinapi_value AsyncCall::SyncCall(napi_env env, AsyncCall::Context::ExecAction exec)
84bc03f14fSopenharmony_ci{
85bc03f14fSopenharmony_ci    if ((context_ == nullptr) || (context_->ctx == nullptr)) {
86bc03f14fSopenharmony_ci        PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "context_ or context_->ctx is null");
87bc03f14fSopenharmony_ci        return nullptr;
88bc03f14fSopenharmony_ci    }
89bc03f14fSopenharmony_ci    context_->ctx->exec_ = std::move(exec);
90bc03f14fSopenharmony_ci    napi_value promise = nullptr;
91bc03f14fSopenharmony_ci    if (context_->callback == nullptr) {
92bc03f14fSopenharmony_ci        napi_create_promise(env, &context_->defer, &promise);
93bc03f14fSopenharmony_ci    } else {
94bc03f14fSopenharmony_ci        napi_get_undefined(env, &promise);
95bc03f14fSopenharmony_ci    }
96bc03f14fSopenharmony_ci    AsyncCall::OnExecute(env, context_);
97bc03f14fSopenharmony_ci    AsyncCall::OnComplete(env, napi_ok, context_);
98bc03f14fSopenharmony_ci    return promise;
99bc03f14fSopenharmony_ci}
100bc03f14fSopenharmony_ci
101bc03f14fSopenharmony_civoid AsyncCall::OnExecute(napi_env env, void *data)
102bc03f14fSopenharmony_ci{
103bc03f14fSopenharmony_ci    AsyncContext *context = reinterpret_cast<AsyncContext *>(data);
104bc03f14fSopenharmony_ci    context->ctx->Exec();
105bc03f14fSopenharmony_ci}
106bc03f14fSopenharmony_ci
107bc03f14fSopenharmony_civoid AsyncCall::OnComplete(napi_env env, napi_status status, void *data)
108bc03f14fSopenharmony_ci{
109bc03f14fSopenharmony_ci    AsyncContext *context = reinterpret_cast<AsyncContext *>(data);
110bc03f14fSopenharmony_ci    napi_value output = nullptr;
111bc03f14fSopenharmony_ci    napi_status runStatus = (*context->ctx)(env, &output);
112bc03f14fSopenharmony_ci    napi_value result[ARG_BUTT] = { 0 };
113bc03f14fSopenharmony_ci    PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI,
114bc03f14fSopenharmony_ci        "run the js callback function:status[%{public}d]runStatus[%{public}d]", status, runStatus);
115bc03f14fSopenharmony_ci    if (status == napi_ok && runStatus == napi_ok) {
116bc03f14fSopenharmony_ci        napi_get_undefined(env, &result[ARG_ERROR]);
117bc03f14fSopenharmony_ci        if (output != nullptr) {
118bc03f14fSopenharmony_ci            result[ARG_DATA] = output;
119bc03f14fSopenharmony_ci        } else {
120bc03f14fSopenharmony_ci            PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "AsyncCall::OnComplete output == nullptr");
121bc03f14fSopenharmony_ci            napi_get_undefined(env, &result[ARG_DATA]);
122bc03f14fSopenharmony_ci        }
123bc03f14fSopenharmony_ci    } else {
124bc03f14fSopenharmony_ci        napi_value errCode = nullptr;
125bc03f14fSopenharmony_ci        napi_value message = nullptr;
126bc03f14fSopenharmony_ci        std::string errMsg("async call failed");
127bc03f14fSopenharmony_ci        if (context->ctx->errCode_ != 0) {
128bc03f14fSopenharmony_ci            napi_create_string_utf8(env, std::to_string(context->ctx->errCode_).c_str(), NAPI_AUTO_LENGTH, &errCode);
129bc03f14fSopenharmony_ci        }
130bc03f14fSopenharmony_ci        if (!context->ctx->errMsg_.empty()) {
131bc03f14fSopenharmony_ci            errMsg = context->ctx->errMsg_;
132bc03f14fSopenharmony_ci        }
133bc03f14fSopenharmony_ci        napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &message);
134bc03f14fSopenharmony_ci        napi_create_error(env, errCode, message, &result[ARG_ERROR]);
135bc03f14fSopenharmony_ci        napi_get_undefined(env, &result[ARG_DATA]);
136bc03f14fSopenharmony_ci    }
137bc03f14fSopenharmony_ci    if (context->defer != nullptr) {
138bc03f14fSopenharmony_ci        // promise
139bc03f14fSopenharmony_ci        if (status == napi_ok && runStatus == napi_ok) {
140bc03f14fSopenharmony_ci            napi_resolve_deferred(env, context->defer, result[ARG_DATA]);
141bc03f14fSopenharmony_ci        } else {
142bc03f14fSopenharmony_ci            napi_reject_deferred(env, context->defer, result[ARG_ERROR]);
143bc03f14fSopenharmony_ci        }
144bc03f14fSopenharmony_ci    } else {
145bc03f14fSopenharmony_ci        // callback
146bc03f14fSopenharmony_ci        PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "Callback to do!");
147bc03f14fSopenharmony_ci        napi_value callback = nullptr;
148bc03f14fSopenharmony_ci        napi_get_reference_value(env, context->callback, &callback);
149bc03f14fSopenharmony_ci        napi_value returnValue;
150bc03f14fSopenharmony_ci        napi_call_function(env, nullptr, callback, ARG_BUTT, result, &returnValue);
151bc03f14fSopenharmony_ci    }
152bc03f14fSopenharmony_ci    DeleteContext(env, context);
153bc03f14fSopenharmony_ci}
154bc03f14fSopenharmony_civoid AsyncCall::DeleteContext(napi_env env, AsyncContext *context)
155bc03f14fSopenharmony_ci{
156bc03f14fSopenharmony_ci    if (env != nullptr) {
157bc03f14fSopenharmony_ci        napi_delete_reference(env, context->callback);
158bc03f14fSopenharmony_ci        napi_delete_reference(env, context->self);
159bc03f14fSopenharmony_ci        napi_delete_async_work(env, context->work);
160bc03f14fSopenharmony_ci    }
161bc03f14fSopenharmony_ci    delete context;
162bc03f14fSopenharmony_ci}
163bc03f14fSopenharmony_ci} // namespace OHOS::MiscServicesNapi