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 #ifndef LOG_TAG
16 #define LOG_TAG "bt_napi_async_callback"
17 #endif
18
19 #include "napi_async_callback.h"
20 #include "bluetooth_errorcode.h"
21 #include "bluetooth_log.h"
22
23 namespace OHOS {
24 namespace Bluetooth {
CallFunction(int errCode,const std::shared_ptr<NapiNativeObject> & object)25 void NapiAsyncCallback::CallFunction(int errCode, const std::shared_ptr<NapiNativeObject> &object)
26 {
27 if (callback == nullptr && promise == nullptr) {
28 HILOGE("callback & promise is nullptr");
29 return;
30 }
31 if (object == nullptr) {
32 HILOGE("napi native object is nullptr");
33 return;
34 }
35
36 if (callback) {
37 callback->CallFunction(errCode, object);
38 return;
39 }
40 if (promise) {
41 promise->ResolveOrReject(errCode, object);
42 }
43 }
44
GetRet(void)45 napi_value NapiAsyncCallback::GetRet(void)
46 {
47 if (promise) {
48 return promise->GetPromise();
49 }
50 return NapiGetUndefinedRet(env);
51 }
52
NapiCallback(napi_env env,napi_value callback)53 NapiCallback::NapiCallback(napi_env env, napi_value callback) : env_(env)
54 {
55 // Use ID to identify NAPI callback.
56 static int idCount = 0;
57 id_ = idCount++;
58
59 auto status = napi_create_reference(env, callback, 1, &callbackRef_);
60 if (status != napi_ok) {
61 HILOGE("napi_create_reference failed, status: %{public}d", status);
62 }
63 }
~NapiCallback()64 NapiCallback::~NapiCallback()
65 {
66 auto status = napi_delete_reference(env_, callbackRef_);
67 if (status != napi_ok) {
68 HILOGE("napi_delete_reference failed, status: %{public}d", status);
69 }
70 }
71
72 namespace {
NapiCallFunction(napi_env env,napi_ref callbackRef,napi_value * argv,size_t argc)73 void NapiCallFunction(napi_env env, napi_ref callbackRef, napi_value *argv, size_t argc)
74 {
75 napi_value undefined = nullptr;
76 napi_value callRet = nullptr;
77 napi_value callback = nullptr;
78 auto status = napi_get_reference_value(env, callbackRef, &callback);
79 if (status != napi_ok) {
80 HILOGE("napi_get_reference_value failed, status: %{public}d", status);
81 return;
82 }
83
84 status = napi_call_function(env, undefined, callback, argc, argv, &callRet);
85 if (status != napi_ok) {
86 HILOGE("napi_call_function failed, status: %{public}d", status);
87 }
88
89 // Check whether the JS application triggers an exception in callback. If it is, clear it.
90 bool isExist = false;
91 status = napi_is_exception_pending(env, &isExist);
92 HILOGD("napi_is_exception_pending status: %{public}d, isExist: %{public}d", status, isExist);
93 if (isExist) {
94 HILOGI("Clear JS application's exception");
95 napi_value exception = nullptr;
96 status = napi_get_and_clear_last_exception(env, &exception);
97 HILOGD("napi_get_and_clear_last_exception status: %{public}d", status);
98 }
99 }
100 } // namespace {}
101
CallFunction(const std::shared_ptr<NapiNativeObject> & object)102 void NapiCallback::CallFunction(const std::shared_ptr<NapiNativeObject> &object)
103 {
104 if (object == nullptr) {
105 HILOGE("napi native object is nullptr");
106 return;
107 }
108
109 NapiHandleScope scope(env_);
110 napi_value val = object->ToNapiValue(env_);
111 NapiCallFunction(env_, callbackRef_, &val, ARGS_SIZE_ONE);
112 }
113
CallFunction(int errCode,const std::shared_ptr<NapiNativeObject> & object)114 void NapiCallback::CallFunction(int errCode, const std::shared_ptr<NapiNativeObject> &object)
115 {
116 if (object == nullptr) {
117 HILOGE("napi native object is nullptr");
118 return;
119 }
120
121 NapiHandleScope scope(env_);
122 napi_value code = GetCallbackErrorValue(env_, errCode);
123 napi_value val = object->ToNapiValue(env_);
124 napi_value argv[ARGS_SIZE_TWO] = {code, val};
125 NapiCallFunction(env_, callbackRef_, argv, ARGS_SIZE_TWO);
126 }
127
GetNapiEnv(void)128 napi_env NapiCallback::GetNapiEnv(void)
129 {
130 return env_;
131 }
132
Equal(napi_env env,napi_value & callback) const133 bool NapiCallback::Equal(napi_env env, napi_value &callback) const
134 {
135 if (env != env_) {
136 HILOGD("Callback is not in the same thread, not uqual");
137 return false;
138 }
139 NapiHandleScope scope(env_);
140 napi_value storedCallback = nullptr;
141 napi_get_reference_value(env_, callbackRef_, &storedCallback);
142
143 bool isEqual = false;
144 napi_strict_equals(env_, storedCallback, callback, &isEqual);
145 return isEqual;
146 }
147
ToLogString(void) const148 std::string NapiCallback::ToLogString(void) const
149 {
150 return "callbackId: " + std::to_string(id_);
151 }
152
NapiPromise(napi_env env)153 NapiPromise::NapiPromise(napi_env env) : env_(env)
154 {
155 auto status = napi_create_promise(env, &deferred_, &promise_);
156 if (status != napi_ok) {
157 HILOGE("napi_create_promise failed, status: %{public}d", status);
158 }
159 }
160
ResolveOrReject(int errCode,const std::shared_ptr<NapiNativeObject> & object)161 void NapiPromise::ResolveOrReject(int errCode, const std::shared_ptr<NapiNativeObject> &object)
162 {
163 if (object == nullptr) {
164 HILOGE("napi native object is nullptr");
165 return;
166 }
167
168 if (isResolvedOrRejected_) {
169 HILOGE("napi Resolved Or Rejected");
170 return;
171 }
172
173 NapiHandleScope scope(env_);
174
175 if (errCode == BT_NO_ERROR) {
176 napi_value val = object->ToNapiValue(env_);
177 Resolve(val);
178 } else {
179 napi_value code = GetCallbackErrorValue(env_, errCode);
180 Reject(code);
181 }
182 isResolvedOrRejected_ = true;
183 }
184
Resolve(napi_value resolution)185 void NapiPromise::Resolve(napi_value resolution)
186 {
187 auto status = napi_resolve_deferred(env_, deferred_, resolution);
188 if (status != napi_ok) {
189 HILOGE("napi_resolve_deferred failed, status: %{public}d", status);
190 }
191 }
Reject(napi_value rejection)192 void NapiPromise::Reject(napi_value rejection)
193 {
194 auto status = napi_reject_deferred(env_, deferred_, rejection);
195 if (status != napi_ok) {
196 HILOGE("napi_reject_deferred failed, status: %{public}d", status);
197 }
198 }
GetPromise(void) const199 napi_value NapiPromise::GetPromise(void) const
200 {
201 return promise_;
202 }
203
NapiHandleScope(napi_env env)204 NapiHandleScope::NapiHandleScope(napi_env env) : env_(env)
205 {
206 napi_status status = napi_open_handle_scope(env_, &scope_);
207 if (status != napi_ok) {
208 HILOGE("napi_open_handle_scope failed, status(%{public}d)", status);
209 }
210 }
211
~NapiHandleScope()212 NapiHandleScope::~NapiHandleScope()
213 {
214 napi_status status = napi_close_handle_scope(env_, scope_);
215 if (status != napi_ok) {
216 HILOGE("napi_close_handle_scope failed, status(%{public}d)", status);
217 }
218 }
219
220 } // namespace Bluetooth
221 } // namespace OHOS
222