1 /*
2 * Copyright (c) 2021 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 "async_call.h"
17
18 #include <algorithm>
19
20 #include "global.h"
21 #include "js_utils.h"
22
23 namespace OHOS {
24 namespace MiscServices {
25 constexpr size_t ARGC_MAX = 6;
AsyncCall(napi_env env,napi_callback_info info,std::shared_ptr<Context> context,size_t maxParamCount)26 AsyncCall::AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr<Context> context, size_t maxParamCount)
27 : env_(env)
28 {
29 context_ = new AsyncContext();
30 size_t argc = ARGC_MAX;
31 napi_value self = nullptr;
32 napi_value argv[ARGC_MAX] = { nullptr };
33 NAPI_CALL_RETURN_VOID(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
34 napi_valuetype valueType = napi_undefined;
35 argc = std::min(argc, maxParamCount);
36 if (argc > 0) {
37 napi_typeof(env, argv[argc - 1], &valueType);
38 if (valueType == napi_function) {
39 napi_create_reference(env, argv[argc - 1], 1, &context_->callback);
40 argc = argc - 1;
41 }
42 }
43 NAPI_CALL_RETURN_VOID(env, (*context)(env, argc, argv, self));
44 context_->ctx = std::move(context);
45 napi_create_reference(env, self, 1, &context_->self);
46 }
47
~AsyncCall()48 AsyncCall::~AsyncCall()
49 {
50 if (context_ == nullptr) {
51 return;
52 }
53
54 DeleteContext(env_, context_);
55 }
56
Call(napi_env env,Context::ExecAction exec,const std::string & resourceName)57 napi_value AsyncCall::Call(napi_env env, Context::ExecAction exec, const std::string &resourceName)
58 {
59 if (context_ == nullptr) {
60 IMSA_HILOGE("context_ is null");
61 return nullptr;
62 }
63 if (context_->ctx == nullptr) {
64 IMSA_HILOGE("context_->ctx is null");
65 return nullptr;
66 }
67 context_->ctx->exec_ = std::move(exec);
68 napi_value promise = nullptr;
69 if (context_->callback == nullptr) {
70 napi_create_promise(env, &context_->defer, &promise);
71 } else {
72 napi_get_undefined(env, &promise);
73 }
74 napi_async_work work = context_->work;
75 napi_value resource = nullptr;
76 std::string name = "IMF_" + resourceName;
77 napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource);
78 napi_create_async_work(env, nullptr, resource, AsyncCall::OnExecute, AsyncCall::OnComplete, context_, &work);
79 context_->work = work;
80 context_ = nullptr;
81 napi_queue_async_work_with_qos(env, work, napi_qos_user_initiated);
82 return promise;
83 }
84
SyncCall(napi_env env,AsyncCall::Context::ExecAction exec)85 napi_value AsyncCall::SyncCall(napi_env env, AsyncCall::Context::ExecAction exec)
86 {
87 if ((context_ == nullptr) || (context_->ctx == nullptr)) {
88 IMSA_HILOGE("context_ or context_->ctx is null");
89 return nullptr;
90 }
91 context_->ctx->exec_ = std::move(exec);
92 napi_value promise = nullptr;
93 if (context_->callback == nullptr) {
94 napi_create_promise(env, &context_->defer, &promise);
95 } else {
96 napi_get_undefined(env, &promise);
97 }
98 AsyncCall::OnExecute(env, context_);
99 AsyncCall::OnComplete(env, context_->ctx->status_, context_);
100 return promise;
101 }
102
OnExecute(napi_env env,void * data)103 void AsyncCall::OnExecute(napi_env env, void *data)
104 {
105 AsyncContext *context = reinterpret_cast<AsyncContext *>(data);
106 context->ctx->Exec();
107 }
108
OnComplete(napi_env env,napi_status status,void * data)109 void AsyncCall::OnComplete(napi_env env, napi_status status, void *data)
110 {
111 AsyncContext *context = reinterpret_cast<AsyncContext *>(data);
112 napi_value output = nullptr;
113 napi_status runStatus = (*context->ctx)(env, &output);
114 napi_value result[ARG_BUTT] = { 0 };
115 IMSA_HILOGE("run the js callback function:status[%{public}d]runStatus[%{public}d]", status, runStatus);
116 if (status == napi_ok && runStatus == napi_ok) {
117 napi_get_undefined(env, &result[ARG_ERROR]);
118 if (output != nullptr) {
119 IMSA_HILOGI("AsyncCall::OnComplete output != nullptr");
120 result[ARG_DATA] = output;
121 } else {
122 IMSA_HILOGI("AsyncCall::OnComplete output == nullptr");
123 napi_get_undefined(env, &result[ARG_DATA]);
124 }
125 } else {
126 result[ARG_ERROR] = JsUtils::ToError(env, context->ctx->errorCode_);
127 napi_get_undefined(env, &result[ARG_DATA]);
128 }
129 if (context->defer != nullptr) {
130 if (status == napi_ok && runStatus == napi_ok) {
131 napi_resolve_deferred(env, context->defer, result[ARG_DATA]);
132 } else {
133 napi_reject_deferred(env, context->defer, result[ARG_ERROR]);
134 }
135 } else {
136 napi_value callback = nullptr;
137 napi_get_reference_value(env, context->callback, &callback);
138 napi_value returnValue;
139 napi_call_function(env, nullptr, callback, ARG_BUTT, result, &returnValue);
140 }
141 DeleteContext(env, context);
142 }
143
DeleteContext(napi_env env,AsyncContext * context)144 void AsyncCall::DeleteContext(napi_env env, AsyncContext *context)
145 {
146 if (env != nullptr) {
147 napi_delete_reference(env, context->callback);
148 napi_delete_reference(env, context->self);
149 napi_delete_async_work(env, context->work);
150 }
151 delete context;
152 }
153 } // namespace MiscServices
154 } // namespace OHOS
155