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 "intell_voice_napi_queue.h"
17 #include "intell_voice_common_napi.h"
18 #include "intell_voice_napi_util.h"
19 #include "intell_voice_log.h"
20
21 #define LOG_TAG "IntellVoiceNapiQueue"
22
23 using namespace std;
24
25 namespace OHOS {
26 namespace IntellVoiceNapi {
AsyncContext(napi_env env)27 AsyncContext::AsyncContext(napi_env env) : env_(env)
28 {
29 INTELL_VOICE_LOG_INFO("enter");
30 }
31
~AsyncContext()32 AsyncContext::~AsyncContext()
33 {
34 INTELL_VOICE_LOG_INFO("enter");
35 if (env_ != nullptr) {
36 if (work_ != nullptr) {
37 napi_delete_async_work(env_, work_);
38 }
39 if (callbackRef_ != nullptr) {
40 napi_delete_reference(env_, callbackRef_);
41 }
42 env_ = nullptr;
43 }
44 }
45
GetCbInfo(napi_env env,napi_callback_info info,size_t callBackIndex,CbInfoParser parser)46 bool AsyncContext::GetCbInfo(napi_env env, napi_callback_info info, size_t callBackIndex, CbInfoParser parser)
47 {
48 INTELL_VOICE_LOG_INFO("enter");
49 napi_status status;
50 napi_value jsThis = nullptr;
51 const int32_t refCount = 1;
52 size_t argc = ARGC_MAX;
53 napi_value args[ARGC_MAX] = { nullptr };
54
55 status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
56 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "Failed to get cb info");
57
58 status = napi_unwrap(env, jsThis, &instanceNapi_);
59 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "Failed to get engine napi instance");
60
61 if (argc > callBackIndex) {
62 napi_valuetype valueType = napi_undefined;
63 napi_typeof(env, args[callBackIndex], &valueType);
64 CHECK_CONDITION_RETURN_FALSE((valueType != napi_function), "Failed to get asyncCallback, type mismatch");
65
66 status = napi_create_reference(env, args[callBackIndex], refCount, &callbackRef_);
67 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "Failed to create callback reference");
68 }
69
70 if (parser) {
71 return parser(argc, args);
72 }
73
74 return true;
75 }
76
AsyncWork(napi_env env,shared_ptr<AsyncContext> context,const string & name,AsyncExecute execute)77 napi_value NapiAsync::AsyncWork(napi_env env, shared_ptr<AsyncContext> context, const string &name,
78 AsyncExecute execute)
79 {
80 INTELL_VOICE_LOG_INFO("enter");
81 napi_value result = nullptr;
82 if (context->callbackRef_ == nullptr) {
83 napi_create_promise(env, &context->deferred_, &result);
84 } else {
85 napi_get_undefined(env, &result);
86 }
87
88 napi_value resource = nullptr;
89 napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource);
90 napi_status status = napi_create_async_work(env, nullptr, resource, execute, AsyncCompleteCallback,
91 static_cast<void *>(context.get()), &context->work_);
92 if (status != napi_ok) {
93 INTELL_VOICE_LOG_ERROR("failed to create async work");
94 result = nullptr;
95 return result;
96 }
97
98 status = napi_queue_async_work(env, context->work_);
99 if (status != napi_ok) {
100 INTELL_VOICE_LOG_ERROR("failed to queue async work");
101 result = nullptr;
102 } else {
103 context->contextSp_ = context;
104 }
105
106 return result;
107 }
108
AsyncWork(napi_env env,shared_ptr<AsyncContext> context,const string & name,AsyncExecute execute,napi_async_complete_callback complete)109 napi_value NapiAsync::AsyncWork(napi_env env, shared_ptr<AsyncContext> context, const string &name,
110 AsyncExecute execute, napi_async_complete_callback complete)
111 {
112 INTELL_VOICE_LOG_INFO("enter");
113 napi_value result = nullptr;
114 if (context->callbackRef_ == nullptr) {
115 napi_create_promise(env, &context->deferred_, &result);
116 } else {
117 napi_get_undefined(env, &result);
118 }
119
120 napi_value resource = nullptr;
121 napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource);
122 napi_status status = napi_create_async_work(env, nullptr, resource, execute, complete,
123 static_cast<void *>(context.get()), &context->work_);
124 if (status != napi_ok) {
125 INTELL_VOICE_LOG_ERROR("failed to create async work");
126 result = nullptr;
127 return result;
128 }
129
130 status = napi_queue_async_work(env, context->work_);
131 context->contextSp_ = context;
132
133 return result;
134 }
135
CommonCallbackRoutine(napi_env env,AsyncContext * context,const napi_value & data)136 void NapiAsync::CommonCallbackRoutine(napi_env env, AsyncContext *context, const napi_value &data)
137 {
138 CHECK_CONDITION_RETURN_VOID((context == nullptr), "async context is null");
139
140 if (context->deferred_) {
141 HandlePromise(env, context, data);
142 } else {
143 HandleAsyncCallback(env, context, data);
144 }
145 context->contextSp_.reset();
146 }
147
HandlePromise(napi_env env,AsyncContext * context,const napi_value & data)148 void NapiAsync::HandlePromise(napi_env env, AsyncContext *context, const napi_value &data)
149 {
150 INTELL_VOICE_LOG_INFO("enter");
151 napi_value result = nullptr;
152 napi_value error = nullptr;
153 napi_get_undefined(env, &result);
154 napi_get_undefined(env, &error);
155
156 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
157 result = data;
158 napi_resolve_deferred(env, context->deferred_, result);
159 return;
160 }
161 napi_value errMessage = nullptr;
162 napi_value errCode = nullptr;
163 std::string msg = IntellVoiceCommonNapi::GetMessageByCode(context->result_);
164 napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &errMessage);
165 napi_create_string_utf8(env, std::to_string(context->result_).c_str(), NAPI_AUTO_LENGTH, &errCode);
166 napi_create_error(env, errCode, errMessage, &error);
167 napi_reject_deferred(env, context->deferred_, error);
168 }
169
HandleAsyncCallback(napi_env env,AsyncContext * context,const napi_value & data)170 void NapiAsync::HandleAsyncCallback(napi_env env, AsyncContext *context, const napi_value &data)
171 {
172 napi_value args[ARGC_TWO] = {nullptr, nullptr};
173 napi_value callback = nullptr;
174 napi_value ret = nullptr;
175 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
176 napi_get_undefined(env, &args[ARG_INDEX_0]);
177 args[ARG_INDEX_1] = data;
178 } else {
179 napi_value errMessage = nullptr;
180 napi_value errCode = nullptr;
181 std::string msg = IntellVoiceCommonNapi::GetMessageByCode(context->result_);
182 napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &errMessage);
183 napi_create_string_utf8(env, std::to_string(context->result_).c_str(), NAPI_AUTO_LENGTH, &errCode);
184 napi_create_error(env, errCode, errMessage, &args[ARG_INDEX_0]);
185 napi_get_undefined(env, &args[ARG_INDEX_1]);
186 }
187 napi_get_reference_value(env, context->callbackRef_, &callback);
188 napi_call_function(env, nullptr, callback, ARGC_TWO, args, &ret);
189 }
190
AsyncCompleteCallback(napi_env env,napi_status status,void * data)191 void NapiAsync::AsyncCompleteCallback(napi_env env, napi_status status, void *data)
192 {
193 INTELL_VOICE_LOG_INFO("enter");
194 CHECK_CONDITION_RETURN_VOID((data == nullptr), "async complete callback data is null");
195 napi_value result = nullptr;
196 auto context = static_cast<AsyncContext *>(data);
197
198 if (context->result_ != NAPI_INTELLIGENT_VOICE_SUCCESS) {
199 napi_get_undefined(env, &result);
200 NapiAsync::CommonCallbackRoutine(env, context, result);
201 return;
202 }
203
204 if (context->complete_ != nullptr) {
205 context->complete_(env, context, result);
206 } else {
207 napi_get_undefined(env, &result);
208 }
209 CommonCallbackRoutine(env, context, result);
210 }
211 } // namespace IntellVoiceNapi
212 } // namespace OHOS
213