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 #include <uv.h>
16 #include "bluetooth_utils.h"
17 #include "napi_bluetooth_ble_utils.h"
18 #include "napi_bluetooth_event.h"
19
20 namespace OHOS {
21 namespace Bluetooth {
EventNotify(AsyncEventData * asyncEvent)22 void NapiEvent::EventNotify(AsyncEventData *asyncEvent)
23 {
24 uv_loop_s *loop = nullptr;
25 napi_get_uv_event_loop(asyncEvent->env_, &loop);
26
27 uv_work_t *work = new uv_work_t;
28 if (work == nullptr) {
29 HILOGI("uv_work_t work is null.");
30 delete asyncEvent;
31 asyncEvent = nullptr;
32 return;
33 }
34 work->data = asyncEvent;
35
36 uv_queue_work(
37 loop,
38 work,
39 [](uv_work_t *work) {},
40 [](uv_work_t *work, int status) {
41 AsyncEventData *callbackInfo = static_cast<AsyncEventData*>(work->data);
42 napi_value callback = nullptr;
43 napi_status ret = napi_get_reference_value(callbackInfo->env_, callbackInfo->callback_, &callback);
44 if (ret == napi_ok && callback != nullptr) {
45 napi_value result = nullptr;
46 napi_value undefined = nullptr;
47 napi_value callResult = nullptr;
48 if (napi_get_undefined(callbackInfo->env_, &undefined) == napi_ok) {
49 result = callbackInfo->packResult();
50 if (result != nullptr) {
51 napi_call_function(callbackInfo->env_, undefined, callback, ARGS_SIZE_ONE,
52 &result, &callResult);
53 }
54 }
55 }
56 delete callbackInfo;
57 delete work;
58 work = nullptr;
59 }
60 );
61 }
62
CreateResult(const std::shared_ptr<BluetoothCallbackInfo> & cb,int value)63 napi_value NapiEvent::CreateResult(const std::shared_ptr<BluetoothCallbackInfo> &cb, int value)
64 {
65 napi_value result = nullptr;
66 if (cb == nullptr) {
67 HILOGE("CreateResult cb is null!");
68 return result;
69 }
70 napi_create_object(cb->env_, &result);
71 ConvertStateChangeParamToJS(cb->env_, result, cb->deviceId_, value);
72 return result;
73 }
74
CreateResult(const std::shared_ptr<BluetoothCallbackInfo> & cb,BluetoothOppTransferInformation & information)75 napi_value NapiEvent::CreateResult(const std::shared_ptr<BluetoothCallbackInfo> &cb,
76 BluetoothOppTransferInformation &information)
77 {
78 napi_value result = nullptr;
79 napi_create_object(cb->env_, &result);
80 ConvertOppTransferInformationToJS(cb->env_, result, information);
81 return result;
82 }
83
84 // if callbackInfos contains specific type, new callbackInfo will cover the old.
85 // If exist, covered event happen, this function will clear rest reference of old callbackInfo in napi framework.
UpdateCallbackInfo(std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> callbackInfos,const std::string & type)86 void UpdateCallbackInfo(std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> callbackInfos,
87 const std::string &type)
88 {
89 auto it = callbackInfos.find(type);
90 if (it != callbackInfos.end() && it->second != nullptr) {
91 HILOGW("repetition type %{public}s is register, old callbackInfo will be deleted.", type.c_str());
92 // as long as the type is same, callbackInfo will be covered.
93 uint32_t refCount = INVALID_REF_COUNT;
94 napi_value handlerTemp = nullptr;
95 napi_status status = napi_get_reference_value(it->second->env_, it->second->callback_, &handlerTemp);
96 if (status != napi_ok) {
97 HILOGE("napi_get_reference_value failed. napi status is %{public}d", status);
98 return;
99 }
100 // if handlerTemp exist clear it. no exist, memory leak safe
101 if (handlerTemp != nullptr) {
102 HILOGI("napi_get_reference_value succeed");
103 napi_reference_unref(it->second->env_, it->second->callback_, &refCount);
104 HILOGI("decrements the refernce count, refCount: %{public}d", refCount);
105 // other place like EventNotify before use will add refCount, happen refCount != 0,
106 // ensure other place copy the prepare covered callbackInfo、add refCount and unref and delete refCount
107 if (refCount == 0) {
108 HILOGI("delete the reference");
109 napi_delete_reference(it->second->env_, it->second->callback_);
110 }
111 HILOGI("old %{public}s is deleted", type.c_str());
112 } else {
113 HILOGI("napi_get_reference_value is nullptr");
114 }
115 }
116 }
117
OnEvent(napi_env env,napi_callback_info info,std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> & callbackInfos)118 napi_value NapiEvent::OnEvent(napi_env env, napi_callback_info info,
119 std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> &callbackInfos)
120 {
121 size_t expectedArgsCount = ARGS_SIZE_TWO;
122 size_t argc = expectedArgsCount;
123 napi_value argv[ARGS_SIZE_TWO] = {0};
124 napi_value thisVar = nullptr;
125
126 napi_value ret = nullptr;
127 napi_get_undefined(env, &ret);
128
129 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
130 if (argc != expectedArgsCount) {
131 HILOGE("Requires 2 argument.");
132 return ret;
133 }
134 std::string type;
135 if (!ParseString(env, type, argv[PARAM0])) {
136 HILOGE("string expected.");
137 return ret;
138 }
139 std::shared_ptr<BluetoothCallbackInfo> callbackInfo = std::make_shared<BluetoothCallbackInfo>();
140 callbackInfo->env_ = env;
141
142 napi_valuetype valueType = napi_undefined;
143 napi_typeof(env, argv[PARAM1], &valueType);
144 if (valueType != napi_function) {
145 HILOGE("Wrong argument type. Function expected.");
146 return ret;
147 }
148
149 UpdateCallbackInfo(callbackInfos, type);
150 napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_);
151 callbackInfos[type] = callbackInfo;
152 HILOGD("%{public}s is registered", type.c_str());
153 return ret;
154 }
155
OffEvent(napi_env env,napi_callback_info info,std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> & callbackInfos)156 napi_value NapiEvent::OffEvent(napi_env env, napi_callback_info info,
157 std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> &callbackInfos)
158 {
159 size_t argc = ARGS_SIZE_ONE;
160 napi_value argv[ARGS_SIZE_TWO] = {0};
161 napi_value thisVar = nullptr;
162
163 napi_value ret = nullptr;
164 napi_get_undefined(env, &ret);
165
166 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
167 if (argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO) {
168 HILOGE("Requires 1 or 2 argument.");
169 return ret;
170 }
171 std::string type;
172 if (!ParseString(env, type, argv[PARAM0])) {
173 HILOGE("string expected.");
174 return ret;
175 }
176 auto it = callbackInfos.find(type);
177 if (it == callbackInfos.end() || it->second == nullptr) {
178 HILOGE("type %{public}s callbackInfos isn't exist.", type.c_str());
179 return ret;
180 }
181 if (env != it->second->env_) {
182 HILOGE("env doesn't match, please check.");
183 return ret;
184 }
185 napi_delete_reference(env, it->second->callback_);
186 it->second = nullptr;
187 HILOGI("%{public}s is unregistered", type.c_str());
188 return ret;
189 }
190 } // namespace Bluetooth
191 } // namespace OHOS