1 /*
2 * Copyright (c) 2022 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 "scan_async_call.h"
17 #include "napi_scan_utils.h"
18 #include "scan_log.h"
19
20 namespace OHOS::Scan {
ScanAsyncCall(napi_env env,napi_callback_info info,std::shared_ptr<Context> context)21 ScanAsyncCall::ScanAsyncCall(napi_env env, napi_callback_info info,
22 std::shared_ptr<Context> context) : env_(env)
23 {
24 if (context == nullptr) {
25 SCAN_HILOGE("context is nullptr");
26 return;
27 }
28 context_ = new (std::nothrow) AsyncContext();
29 if (context_ == nullptr) {
30 SCAN_HILOGE("context_ is nullptr");
31 return;
32 }
33 size_t argc = NapiScanUtils::MAX_ARGC;
34 napi_value self = nullptr;
35 napi_value argv[NapiScanUtils::MAX_ARGC] = { nullptr };
36 SCAN_CALL_RETURN_VOID(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
37 context_->paramStatus = (*context)(env, argc, argv, self);
38 context_->ctx = std::move(context);
39 napi_create_reference(env, self, 1, &context_->self);
40 }
41
~ScanAsyncCall()42 ScanAsyncCall::~ScanAsyncCall()
43 {
44 if (context_ == nullptr) {
45 return;
46 }
47
48 DeleteContext(env_, context_);
49 }
50
Call(napi_env env,Context::ExecAction exec)51 napi_value ScanAsyncCall::Call(napi_env env, Context::ExecAction exec)
52 {
53 SCAN_HILOGD("async call exec");
54 if (context_ != nullptr && context_->ctx != nullptr) {
55 context_->ctx->exec_ = std::move(exec);
56 } else {
57 SCAN_HILOGE("context_ is null or context->ctx is null");
58 return nullptr;
59 }
60 napi_value promise = nullptr;
61 napi_create_promise(env, &context_->defer, &promise);
62 napi_async_work work = context_->work;
63 napi_value resource = nullptr;
64 napi_create_string_utf8(env, "ScanAsyncCall", NAPI_AUTO_LENGTH, &resource);
65 napi_create_async_work(env, nullptr, resource, ScanAsyncCall::OnExecute,
66 ScanAsyncCall::OnComplete, context_, &work);
67 context_->work = work;
68 context_ = nullptr;
69 napi_queue_async_work(env, work);
70 return promise;
71 }
72
OnExecute(napi_env env,void * data)73 void ScanAsyncCall::OnExecute(napi_env env, void *data)
74 {
75 AsyncContext *context = reinterpret_cast<AsyncContext *>(data);
76 if (context == nullptr || context->ctx == nullptr) {
77 SCAN_HILOGE("context->ctx is null");
78 return;
79 }
80
81 SCAN_HILOGD("run the async runnable");
82 if (context->ctx->GetErrorIndex() == E_SCAN_NONE) {
83 context->ctx->Exec();
84 }
85 }
86
PrepareSuccessResult(napi_env env,napi_value output,AsyncResult & result)87 void ScanAsyncCall::PrepareSuccessResult(napi_env env, napi_value output, AsyncResult& result)
88 {
89 napi_get_undefined(env, &result.error);
90 if (output != nullptr) {
91 result.data = output;
92 SCAN_HILOGD("async call napi_ok.");
93 } else {
94 napi_get_undefined(env, &result.data);
95 }
96 }
97
PrepareErrorResult(napi_env env,const AsyncContext * context,AsyncResult & result)98 void ScanAsyncCall::PrepareErrorResult(napi_env env, const AsyncContext* context, AsyncResult& result)
99 {
100 uint32_t errorCode = E_SCAN_GENERIC_FAILURE;
101 if (context->paramStatus != napi_ok) {
102 errorCode = E_SCAN_INVALID_PARAMETER;
103 }
104 if (context->ctx != nullptr) {
105 errorCode = context->ctx->GetErrorIndex();
106 }
107 std::string errorMessage;
108 NapiScanUtils::SetErrorText(errorCode, errorMessage);
109 SCAN_HILOGE("ErrorMessage: [%{public}s], ErrorIndex:[%{public}d]",
110 errorMessage.c_str(), errorCode);
111
112 napi_value businessError = nullptr;
113 napi_create_object(env, &businessError);
114
115 napi_value codeValue = nullptr;
116 napi_create_uint32(env, errorCode, &codeValue);
117 napi_set_named_property(env, businessError, "code", codeValue);
118
119 if (!errorMessage.empty()) {
120 napi_value messageValue = nullptr;
121 napi_create_string_utf8(env, errorMessage.c_str(), errorMessage.length(), &messageValue);
122 napi_set_named_property(env, businessError, "message", messageValue);
123 }
124
125 result.error = businessError;
126 napi_get_undefined(env, &result.data);
127 }
128
OnComplete(napi_env env,napi_status status,void * data)129 void ScanAsyncCall::OnComplete(napi_env env, napi_status status, void *data)
130 {
131 AsyncContext *context = reinterpret_cast<AsyncContext *>(data);
132 if (context == nullptr) {
133 SCAN_HILOGE("OnComplete called with null context");
134 return;
135 }
136 if (context->ctx == nullptr || context->ctx->GetErrorIndex() != E_SCAN_NONE) {
137 status = napi_generic_failure;
138 }
139 napi_value output = nullptr;
140 napi_status runStatus = napi_generic_failure;
141 if (context->ctx != nullptr) {
142 runStatus = (*context->ctx)(env, &output);
143 }
144 SCAN_HILOGD("runStatus: [%{public}d], status: [%{public}d]", runStatus, status);
145 AsyncResult result;
146 if (status == napi_ok && runStatus == napi_ok) {
147 PrepareSuccessResult(env, output, result);
148 } else {
149 PrepareErrorResult(env, context, result);
150 }
151 if (status == napi_ok && runStatus == napi_ok) {
152 napi_resolve_deferred(env, context->defer, result.data);
153 } else {
154 napi_reject_deferred(env, context->defer, result.error);
155 }
156 DeleteContext(env, context);
157 }
158
DeleteContext(napi_env env,AsyncContext * context)159 void ScanAsyncCall::DeleteContext(napi_env env, AsyncContext *context)
160 {
161 if (context == nullptr) {
162 return;
163 }
164 if (context->work != nullptr) {
165 napi_delete_async_work(env, context->work);
166 }
167 if (context->self != nullptr) {
168 napi_delete_reference(env, context->self);
169 }
170 delete context;
171 context = nullptr;
172 }
173 } // namespace OHOS::Scan
174