• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "napi_bluetooth_spp_client.h"
17 #include "securec.h"
18 #include <unistd.h>
19 #include <uv.h>
20 
21 namespace OHOS {
22 namespace Bluetooth {
23 const int sleepTime = 5;
24 std::map<int, std::shared_ptr<NapiSppClient>> NapiSppClient::clientMap;
25 int NapiSppClient::count = 0;
26 
SppConnect(napi_env env,napi_callback_info info)27 napi_value NapiSppClient::SppConnect(napi_env env, napi_callback_info info)
28 {
29     HILOGI("SppConnect called");
30     size_t expectedArgsCount = ARGS_SIZE_THREE;
31     size_t argc = expectedArgsCount;
32     napi_value argv[ARGS_SIZE_THREE] = {0};
33 
34     napi_value ret = nullptr;
35     napi_get_undefined(env, &ret);
36 
37     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
38     if (argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE) {
39         HILOGE("Requires 2 or 3 arguments.");
40         return ret;
41     }
42 
43     std::string deviceId;
44     if (!ParseString(env, deviceId, argv[PARAM0])) {
45         HILOGE("Wrong argument type. String expected.");
46         return ret;
47     }
48 
49     SppConnectCallbackInfo *callbackInfo = new SppConnectCallbackInfo();
50     callbackInfo->env_ = env;
51     callbackInfo->sppOption_ = GetSppOptionFromJS(env, argv[PARAM1]);
52     callbackInfo->deviceId_ = deviceId;
53 
54     napi_value promise = nullptr;
55 
56     if (argc == expectedArgsCount) {
57         // Callback mode
58         HILOGI("SppConnect callback mode");
59         napi_valuetype valueType = napi_undefined;
60         napi_typeof(env, argv[PARAM2], &valueType);
61         if (valueType != napi_function) {
62             HILOGE("Wrong argument type. Function expected.");
63             delete callbackInfo;
64             callbackInfo = nullptr;
65             return ret;
66         }
67         napi_create_reference(env, argv[PARAM2], 1, &callbackInfo->callback_);
68         napi_get_undefined(env, &promise);
69     } else {
70         // Promise mode
71         HILOGI("SppConnect promise mode");
72         napi_create_promise(env, &callbackInfo->deferred_, &promise);
73     }
74 
75     napi_value resource = nullptr;
76     napi_create_string_utf8(env, "SppConnect", NAPI_AUTO_LENGTH, &resource);
77 
78     napi_create_async_work(
79         env, nullptr, resource,
80         [](napi_env env, void* data) {
81             HILOGI("SppConnect execute");
82             SppConnectCallbackInfo* callbackInfo = (SppConnectCallbackInfo*)data;
83             callbackInfo->device_ = std::make_shared<BluetoothRemoteDevice>(callbackInfo->deviceId_, 0);
84             callbackInfo->client_ = std::make_shared<SppClientSocket>(*callbackInfo->device_,
85                 UUID::FromString(callbackInfo->sppOption_->uuid_),
86                 callbackInfo->sppOption_->type_, callbackInfo->sppOption_->secure_);
87             HILOGI("SppConnect client_ constructed");
88             if (callbackInfo->client_->Connect() == BtStatus::BT_SUCCESS) {
89                 HILOGI("SppConnect successfully");
90                 callbackInfo->errorCode_ = CODE_SUCCESS;
91             } else {
92                 HILOGI("SppConnect failed");
93                 callbackInfo->errorCode_ = CODE_FAILED;
94             }
95         },
96         [](napi_env env, napi_status status, void* data) {
97             HILOGI("SppConnect execute back");
98             SppConnectCallbackInfo* callbackInfo = (SppConnectCallbackInfo*)data;
99             napi_value result[ARGS_SIZE_TWO] = {0};
100             napi_value callback = 0;
101             napi_value undefined = 0;
102             napi_value callResult = 0;
103             napi_get_undefined(env, &undefined);
104 
105             if (callbackInfo->errorCode_ == CODE_SUCCESS) {
106                 HILOGI("SppConnect execute back success");
107                 std::shared_ptr<NapiSppClient> client =  std::make_shared<NapiSppClient>();
108                 client->device_ = callbackInfo->device_;
109                 client->id_ = NapiSppClient::count++;
110                 napi_create_int32(env, client->id_, &result[PARAM1]);
111                 client->client_ = callbackInfo->client_;
112                 clientMap.insert(std::make_pair(client->id_, client));
113                 HILOGI("SppConnect execute back successfully");
114             } else {
115                 napi_get_undefined(env, &result[PARAM1]);
116                 HILOGI("SppConnect execute back failed");
117             }
118 
119             if (callbackInfo->callback_) {
120                 // Callback mode
121                 HILOGI("SppConnect execute Callback mode");
122                 result[PARAM0] = GetCallbackErrorValue(callbackInfo->env_, callbackInfo->errorCode_);
123                 napi_get_reference_value(env, callbackInfo->callback_, &callback);
124                 napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, result, &callResult);
125                 napi_delete_reference(env, callbackInfo->callback_);
126             } else {
127                 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
128                 // Promise mode
129                     HILOGI("SppConnect execute Promise mode successfully");
130                     napi_resolve_deferred(env, callbackInfo->deferred_, result[PARAM1]);
131                 } else {
132                     HILOGI("SppConnect execute Promise mode failed");
133                     napi_reject_deferred(env, callbackInfo->deferred_, result[PARAM1]);
134                 }
135             }
136             napi_delete_async_work(env, callbackInfo->asyncWork_);
137             delete callbackInfo;
138             callbackInfo = nullptr;
139         },
140         (void*)callbackInfo,
141         &callbackInfo->asyncWork_);
142     napi_queue_async_work(env, callbackInfo->asyncWork_);
143     return ret;
144 }
145 
SppCloseClientSocket(napi_env env,napi_callback_info info)146 napi_value NapiSppClient::SppCloseClientSocket(napi_env env, napi_callback_info info)
147 {
148     HILOGI("SppCloseClientSocket called");
149     size_t expectedArgsCount = ARGS_SIZE_ONE;
150     size_t argc = expectedArgsCount;
151     napi_value argv[ARGS_SIZE_ONE] = {0};
152     napi_value thisVar = nullptr;
153     bool isOK = false;
154     napi_value ret = nullptr;
155 
156     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
157     if (argc != expectedArgsCount) {
158         HILOGE("Requires 1 argument.");
159         return ret;
160     }
161 
162     std::shared_ptr<NapiSppClient> client = nullptr;
163     int id =  -1;
164     ParseInt32(env, id, argv[PARAM0]);
165 
166     if (clientMap[id]) {
167         client = clientMap[id];
168     } else {
169         HILOGE("no such key in map.");
170         return ret;
171     }
172 
173     if (client->client_) {
174         client->client_->Close();
175         isOK = true;
176     }
177     clientMap.erase(id);
178     napi_get_boolean(env, isOK, &ret);
179     return ret;
180 }
181 
SppWrite(napi_env env,napi_callback_info info)182 napi_value NapiSppClient::SppWrite(napi_env env, napi_callback_info info)
183 {
184     napi_value ret = nullptr;
185     napi_get_undefined(env, &ret);
186     size_t expectedArgsCount = ARGS_SIZE_TWO;
187     size_t argc = expectedArgsCount;
188     napi_value argv[ARGS_SIZE_TWO] = {0};
189     napi_value thisVar = nullptr;
190     char* totalBuf = nullptr;
191     size_t totalSize = 0;
192     bool isOK = false;
193     int id = -1;
194     napi_get_boolean(env, isOK, &ret);
195 
196     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
197     if (argc != expectedArgsCount) {
198         HILOGE("Requires 3 argument.");
199         return ret;
200     }
201 
202     ParseInt32(env, id, argv[PARAM0]);
203 
204     if (!ParseArrayBuffer(env, (uint8_t**)(&totalBuf), totalSize, argv[PARAM1])) {
205         HILOGE("ParseArrayBuffer failed");
206         return ret;
207     }
208 
209     if (clientMap[id]) {
210         OHOS::Bluetooth::OutputStream outputStream = clientMap[id]->client_->GetOutputStream();
211 
212         while (totalSize) {
213             int result = outputStream.Write(totalBuf, totalSize);
214             if (result > 0) {
215                 totalSize = totalSize - result;
216                 totalBuf += result;
217                 isOK = true;
218             } else if (result < 0) {
219                 HILOGI("Write socket exception!");
220                 return ret;
221             }
222         }
223     } else {
224         HILOGI("Client socket not exit!");
225     }
226     napi_get_boolean(env, isOK, &ret);
227     return ret;
228 }
On(napi_env env,napi_callback_info info)229 void NapiSppClient::On(napi_env env, napi_callback_info info)
230 {
231     HILOGI("On is called");
232 
233     size_t expectedArgsCount = ARGS_SIZE_THREE;
234     size_t argc = expectedArgsCount;
235     napi_value argv[ARGS_SIZE_THREE] = {0};
236     napi_value thisVar = nullptr;
237     int id = -1;
238 
239     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
240     if (argc != expectedArgsCount) {
241         HILOGE("Requires 3 argument.");
242         return;
243     }
244     std::string type;
245     ParseString(env, type, argv[PARAM0]);
246     std::shared_ptr<BluetoothCallbackInfo> callbackInfo;
247     if (type.c_str() == STR_BT_SPP_READ) {
248         callbackInfo = std::make_shared<BufferCallbackInfo>();
249     } else {
250         callbackInfo = std::make_shared<BluetoothCallbackInfo>();
251     }
252     callbackInfo->env_ = env;
253 
254     napi_valuetype valueType1 = napi_undefined;
255     napi_valuetype valueType2 = napi_undefined;
256     napi_typeof(env, argv[PARAM1], &valueType1);
257     napi_typeof(env, argv[PARAM2], &valueType2);
258     if (valueType1 != napi_number && valueType2 != napi_function) {
259         HILOGE("Wrong argument type. Function expected.");
260         return;
261     }
262 
263     napi_create_reference(env, argv[PARAM2], 1, &callbackInfo->callback_);
264 
265     ParseInt32(env, id, argv[PARAM1]);
266     std::shared_ptr<NapiSppClient> client = clientMap[id];
267     if (!client) {
268         HILOGI("client is nullptr");
269         return;
270     }
271     client->sppReadFlag = true;
272     client->callbackInfos_[type] = callbackInfo;
273     HILOGI("sppRead begin");
274     client->thread_ = std::make_shared<std::thread>(sppRead, id);
275     client->thread_->detach();
276     return;
277 }
278 
Off(napi_env env,napi_callback_info info)279 void NapiSppClient::Off(napi_env env, napi_callback_info info)
280 {
281     size_t expectedArgsCount = ARGS_SIZE_THREE;
282     size_t argc = expectedArgsCount;
283     napi_value argv[ARGS_SIZE_THREE] = {0};
284     napi_value thisVar = nullptr;
285     int id = -1;
286 
287     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
288     if (argc != expectedArgsCount) {
289         HILOGE("Requires 3 argument.");
290         return;
291     }
292 
293     std::string type;
294     ParseString(env, type, argv[PARAM0]);
295 
296     ParseInt32(env, id, argv[PARAM1]);
297     std::shared_ptr<NapiSppClient> client = clientMap[id];
298     if (!client) {
299         HILOGI("client is nullptr");
300         return;
301     }
302     client->callbackInfos_[type] = nullptr;
303     client->sppReadFlag = false;
304     sleep(sleepTime);
305     return;
306 }
307 
sppRead(int id)308 void NapiSppClient::sppRead(int id)
309 {
310     HILOGI("sppRead is called");
311     OHOS::Bluetooth::InputStream inputStream = clientMap[id]->client_->GetInputStream();
312     char buf[1024];
313     int ret = 0;
314     bool isRead = true;
315     while (isRead) {
316         if (clientMap[id] == nullptr) {
317             isRead = false;
318             break;
319         }
320         isRead = clientMap[id]->sppReadFlag;
321         HILOGI("inputStream.Read start");
322         while (true) {
323             memset_s(buf, sizeof(buf), 0, sizeof(buf));
324             ret = inputStream.Read(buf, sizeof(buf));
325             HILOGI("inputStream.Read end");
326             if (ret <= 0) {
327                 HILOGI("inputStream.Read failed");
328                 isRead = false;
329                 break;
330             } else {
331                 HILOGI("napi_call_function begin");
332                 std::shared_ptr<BufferCallbackInfo> callbackInfo =
333                     std::static_pointer_cast<BufferCallbackInfo>(clientMap[id]->callbackInfos_[STR_BT_SPP_READ]);
334 
335                 callbackInfo->info_ = ret;
336                 memcpy_s(callbackInfo->buffer_, sizeof(callbackInfo->buffer_), buf, ret);
337 
338                 uv_loop_s *loop = nullptr;
339                 napi_get_uv_event_loop(callbackInfo->env_, &loop);
340                 uv_work_t *work = new uv_work_t;
341                 work->data = (void*)callbackInfo.get();
342 
343                 uv_queue_work(
344                     loop,
345                     work,
346                     [](uv_work_t *work) {},
347                     [](uv_work_t *work, int status) {
348                         BufferCallbackInfo *callbackInfo = (BufferCallbackInfo *)work->data;
349                         int size = callbackInfo->info_;
350                         uint8_t* totalBuf = (uint8_t*) malloc(size);
351                         memcpy_s(totalBuf, size, callbackInfo->buffer_, size);
352                         napi_value result = nullptr;
353                         uint8_t* bufferData = nullptr;
354                         napi_create_arraybuffer(callbackInfo->env_ , size, (void**)&bufferData, &result);
355                         memcpy_s(bufferData, size, totalBuf, size);
356                         free(totalBuf);
357 
358                         napi_value callback = nullptr;
359                         napi_value undefined = nullptr;
360                         napi_value callResult = nullptr;
361                         napi_get_undefined(callbackInfo->env_, &undefined);
362                         napi_get_reference_value(callbackInfo->env_, callbackInfo->callback_, &callback);
363                         napi_call_function(callbackInfo->env_, undefined, callback, ARGS_SIZE_ONE, &result, &callResult);
364                         delete work;
365                         work = nullptr;
366                     }
367                 );
368             }
369         }
370     }
371     return;
372 }
373 } // namespace Bluetooth
374 } // namespace OHOS