• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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