• 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 
16 #include <unistd.h>
17 #include <cinttypes>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <optional>
21 #include <string>
22 #include <map>
23 #include <vector>
24 #include <uv.h>
25 
26 #include "napi_remote_object.h"
27 #include "ext_permission_manager.h"
28 #include "device_manager_middle.h"
29 
30 namespace OHOS {
31 namespace ExternalDeviceManager {
32 constexpr int32_t PARAM_COUNT_1 = 1;
33 constexpr int32_t PARAM_COUNT_2 = 2;
34 constexpr int32_t PARAM_COUNT_3 = 3;
35 constexpr uint64_t MAX_JS_NUMBER = 9007199254740991;
36 
37 static const std::map<int32_t, std::string> ERROR_MESSAGES = {
38     {SERVICE_EXCEPTION,  "ExternalDeviceManager service exception."},
39     {PERMISSION_DENIED,  "Permission denied."},
40     {PARAMETER_ERROR,  "The parameter check failed."},
41 };
42 
43 static std::mutex mapMutex;
44 static std::map<uint64_t, sptr<AsyncData>> g_callbackMap = {};
45 static DriverExtMgrClient &g_edmClient = DriverExtMgrClient::GetInstance();
46 static sptr<DeviceManagerCallback> g_edmCallback = new (std::nothrow) DeviceManagerCallback {};
47 static const std::string PERMISSION_NAME = "ohos.permission.ACCESS_EXTENSIONAL_DEVICE_DRIVER";
48 
49 static napi_value ConvertToBusinessError(const napi_env &env, const ErrMsg &errMsg);
50 static napi_value ConvertToJsDeviceId(const napi_env &env, uint64_t deviceId);
51 static napi_value GetCallbackResult(const napi_env &env, uint64_t deviceId, const sptr<IRemoteObject> &drvExtObj);
52 
BindDeviceWorkCb(uv_work_t * work,int status)53 static void BindDeviceWorkCb(uv_work_t *work, int status)
54 {
55     if (work == nullptr) {
56         return;
57     }
58     sptr<AsyncData> data(reinterpret_cast<AsyncData *>(work->data));
59     data->DecStrongRef(nullptr);
60     delete work;
61 
62     napi_value result = GetCallbackResult(data->env, data->deviceId, data->drvExtObj);
63     napi_value err = ConvertToBusinessError(data->env, data->errMsg);
64     if (data->bindCallback != nullptr) {
65         napi_value callback;
66         napi_get_reference_value(data->env, data->bindCallback, &callback);
67         napi_value argv[PARAM_COUNT_2] = {err, result};
68         napi_value callResult;
69         napi_call_function(data->env, nullptr, callback, PARAM_COUNT_2, argv, &callResult);
70         EDM_LOGI(MODULE_DEV_MGR, "bind device callback finish.");
71     } else if (data->bindDeferred != nullptr) {
72         if (data->errMsg.IsOk()) {
73             napi_resolve_deferred(data->env, data->bindDeferred, result);
74         } else {
75             napi_reject_deferred(data->env, data->bindDeferred, err);
76         }
77         EDM_LOGI(MODULE_DEV_MGR, "bind device promise finish.");
78     }
79 }
80 
UvDeleteRef(uv_work_t * work,int status)81 void UvDeleteRef(uv_work_t *work, int status)
82 {
83     if (work == nullptr) {
84         return;
85     }
86     AsyncDataWorker *data = static_cast<AsyncDataWorker *>(work->data);
87     if (data == nullptr) {
88         delete work;
89         work = nullptr;
90         return;
91     }
92     if (data->bindCallback != nullptr) {
93         napi_delete_reference(data->env, data->bindCallback);
94     }
95     if (data->onDisconnect != nullptr) {
96         napi_delete_reference(data->env, data->onDisconnect);
97     }
98     if (data->unbindCallback != nullptr) {
99         napi_delete_reference(data->env, data->unbindCallback);
100     }
101     delete data;
102     data = nullptr;
103     delete work;
104 }
105 
DeleteNapiRef()106 void AsyncData::DeleteNapiRef()
107 {
108     if (env == nullptr) {
109         return;
110     }
111     uv_loop_t* loop = nullptr;
112     NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
113     AsyncDataWorker *data = new (std::nothrow) AsyncDataWorker();
114     if (data == nullptr) {
115         EDM_LOGE(MODULE_DEV_MGR, "new AsyncDataWorker fail");
116         return;
117     }
118     data->env = env;
119     data->bindCallback = bindCallback;
120     data->onDisconnect = onDisconnect;
121     data->unbindCallback = unbindCallback;
122 
123     uv_work_t *work = new (std::nothrow) uv_work_t;
124     if (work == nullptr) {
125         EDM_LOGE(MODULE_DEV_MGR, "new work fail");
126         delete data;
127         data = nullptr;
128         return;
129     }
130     work->data = static_cast<void *>(data);
131     auto ret = uv_queue_work(
132         loop, work, [](uv_work_t *work) {}, UvDeleteRef);
133     if (ret != 0) {
134         delete data;
135         data = nullptr;
136         delete work;
137         work = nullptr;
138     }
139 }
140 
141 
OnConnect(uint64_t deviceId,const sptr<IRemoteObject> & drvExtObj,const ErrMsg & errMsg)142 void DeviceManagerCallback::OnConnect(uint64_t deviceId, const sptr<IRemoteObject> &drvExtObj, const ErrMsg &errMsg)
143 {
144     EDM_LOGE(MODULE_DEV_MGR, "bind device callback: %{public}016" PRIX64, deviceId);
145     std::lock_guard<std::mutex> mapLock(mapMutex);
146     if (g_callbackMap.count(deviceId) == 0) {
147         EDM_LOGE(MODULE_DEV_MGR, "device OnConnect is null");
148         return;
149     }
150 
151     auto asyncData = g_callbackMap[deviceId];
152     if (!errMsg.IsOk()) {
153         g_callbackMap.erase(deviceId);
154     }
155     uv_loop_t* loop = nullptr;
156     NAPI_CALL_RETURN_VOID(asyncData->env, napi_get_uv_event_loop(asyncData->env, &loop));
157     uv_work_t* work = new (std::nothrow) uv_work_t;
158     if (work == nullptr) {
159         EDM_LOGE(MODULE_DEV_MGR, "new work fail");
160         return;
161     }
162     asyncData->drvExtObj = drvExtObj;
163     asyncData->errMsg = errMsg;
164     asyncData->IncStrongRef(nullptr);
165     work->data = asyncData.GetRefPtr();
166     auto ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, BindDeviceWorkCb);
167     if (ret != 0) {
168         delete work;
169         asyncData->DecStrongRef(nullptr);
170     }
171 }
172 
DisConnectWorkCb(uv_work_t * work,int status)173 static void DisConnectWorkCb(uv_work_t *work, int status)
174 {
175     if (work == nullptr) {
176             return;
177         }
178         sptr<AsyncData> data(reinterpret_cast<AsyncData*>(work->data));
179         data->DecStrongRef(nullptr);
180         delete work;
181 
182         napi_value disConnCallback;
183         napi_status napiSatus = napi_get_reference_value(data->env, data->onDisconnect, &disConnCallback);
184         if (napiSatus == napi_ok) {
185             napi_value err = ConvertToBusinessError(data->env, data->errMsg);
186             napi_value result = ConvertToJsDeviceId(data->env, data->deviceId);
187             napi_value argv[PARAM_COUNT_2] = {err, result};
188             napi_value callResult;
189             napi_call_function(data->env, nullptr, disConnCallback, PARAM_COUNT_2, argv, &callResult);
190             EDM_LOGI(MODULE_DEV_MGR, "onDisconnect callback finish.");
191         }
192 
193         napi_value err = ConvertToBusinessError(data->env, data->unBindErrMsg);
194         napi_value result = ConvertToJsDeviceId(data->env, data->deviceId);
195         if (data->unbindCallback != nullptr) {
196             napi_value callback;
197             NAPI_CALL_RETURN_VOID(data->env, napi_get_reference_value(data->env, data->unbindCallback, &callback));
198 
199             napi_value argv[PARAM_COUNT_2] = {err, result};
200             napi_value callResult;
201             napi_call_function(data->env, nullptr, callback, PARAM_COUNT_2, argv, &callResult);
202             EDM_LOGI(MODULE_DEV_MGR, "unbind device callback finish.");
203         } else if (data->unbindDeferred != nullptr) {
204             if (data->unBindErrMsg.IsOk()) {
205                 napi_resolve_deferred(data->env, data->unbindDeferred, result);
206             } else {
207                 napi_reject_deferred(data->env, data->unbindDeferred, err);
208             }
209             EDM_LOGI(MODULE_DEV_MGR, "unbind device promise finish.");
210         }
211 }
212 
OnDisconnect(uint64_t deviceId,const ErrMsg & errMsg)213 void DeviceManagerCallback::OnDisconnect(uint64_t deviceId, const ErrMsg &errMsg)
214 {
215     EDM_LOGE(MODULE_DEV_MGR, "device onDisconnect: %{public}016" PRIX64, deviceId);
216     std::lock_guard<std::mutex> mapLock(mapMutex);
217     if (g_callbackMap.count(deviceId) == 0) {
218         EDM_LOGE(MODULE_DEV_MGR, "device callback map is null");
219         return;
220     }
221 
222     auto asyncData = g_callbackMap[deviceId];
223     g_callbackMap.erase(deviceId);
224     if (asyncData == nullptr || (asyncData->onDisconnect == nullptr && asyncData->unbindCallback == nullptr
225         && asyncData->unbindDeferred == nullptr)) {
226         EDM_LOGE(MODULE_DEV_MGR, "device callback is null");
227         return;
228     }
229     uv_loop_t* loop = nullptr;
230     NAPI_CALL_RETURN_VOID(asyncData->env, napi_get_uv_event_loop(asyncData->env, &loop));
231     uv_work_t* work = new (std::nothrow) uv_work_t;
232     if (work == nullptr) {
233         EDM_LOGE(MODULE_DEV_MGR, "new work fail");
234         return;
235     }
236     asyncData->errMsg = errMsg;
237     asyncData->IncStrongRef(nullptr);
238     work->data = asyncData.GetRefPtr();
239     auto ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, DisConnectWorkCb);
240     if (ret != 0) {
241         delete work;
242         asyncData->DecStrongRef(nullptr);
243     }
244 }
245 
OnUnBind(uint64_t deviceId,const ErrMsg & errMsg)246 void DeviceManagerCallback::OnUnBind(uint64_t deviceId, const ErrMsg &errMsg)
247 {
248     EDM_LOGI(MODULE_DEV_MGR, "unbind device callback: %{public}016" PRIX64, deviceId);
249     std::lock_guard<std::mutex> mapLock(mapMutex);
250     if (g_callbackMap.count(deviceId) == 0) {
251         EDM_LOGE(MODULE_DEV_MGR, "device unbind map is null");
252         return;
253     }
254 
255     auto asyncData = g_callbackMap[deviceId];
256     if (asyncData == nullptr || (asyncData->unbindCallback == nullptr && asyncData->unbindDeferred == nullptr)) {
257         EDM_LOGE(MODULE_DEV_MGR, "device unbind is null");
258         return;
259     }
260     asyncData->unBindErrMsg = errMsg;
261 }
262 
IsMatchType(const napi_env & env,const napi_value & value,const napi_valuetype & type)263 static bool IsMatchType(const napi_env &env, const napi_value &value, const napi_valuetype &type)
264 {
265     napi_valuetype paramType = napi_undefined;
266     napi_typeof(env, value, &paramType);
267     return paramType == type;
268 }
269 
GetCallbackResult(const napi_env & env,uint64_t deviceId,const sptr<IRemoteObject> & drvExtObj)270 static napi_value GetCallbackResult(const napi_env &env, uint64_t deviceId, const sptr<IRemoteObject> &drvExtObj)
271 {
272     napi_value id = ConvertToJsDeviceId(env, deviceId);
273 
274     napi_value remoteObj;
275     if (drvExtObj == nullptr) {
276         napi_get_undefined(env, &remoteObj);
277         EDM_LOGE(MODULE_DEV_MGR, "Remote obj is null.");
278     } else {
279         EDM_LOGI(MODULE_DEV_MGR, "Remote obj create.");
280         remoteObj = NAPI_ohos_rpc_CreateJsRemoteObject(env, drvExtObj);
281     }
282 
283     napi_value result;
284     napi_create_object(env, &result);
285     napi_set_named_property(env, result, "deviceId", id);
286     napi_set_named_property(env, result, "remote", remoteObj);
287 
288     return result;
289 }
290 
GetNapiError(int32_t errorCode)291 static std::optional<std::string> GetNapiError(int32_t errorCode)
292 {
293     auto iter = ERROR_MESSAGES.find(errorCode);
294     if (iter != ERROR_MESSAGES.end()) {
295         return iter->second;
296     }
297     return std::nullopt;
298 }
299 
CreateBusinessError(const napi_env & env,const int32_t errCode,const std::string & errMessage)300 static napi_value CreateBusinessError(const napi_env &env, const int32_t errCode, const std::string &errMessage)
301 {
302     napi_value businessError = nullptr;
303     napi_value code = nullptr;
304     napi_value msg = nullptr;
305     NAPI_CALL(env, napi_create_int32(env, errCode, &code));
306     NAPI_CALL(env, napi_create_string_utf8(env, errMessage.c_str(), NAPI_AUTO_LENGTH, &msg));
307     napi_create_error(env, nullptr, msg, &businessError);
308     napi_set_named_property(env, businessError, "code", code);
309     napi_set_named_property(env, businessError, "message", msg);
310     return businessError;
311 }
312 
ConvertToBusinessError(const napi_env & env,const ErrMsg & errMsg)313 static napi_value ConvertToBusinessError(const napi_env &env, const ErrMsg &errMsg)
314 {
315     napi_value businessError = nullptr;
316     if (errMsg.IsOk()) {
317         napi_get_undefined(env, &businessError);
318         return businessError;
319     }
320 
321     auto msgString = GetNapiError(SERVICE_EXCEPTION);
322     if (!msgString) {
323         napi_get_undefined(env, &businessError);
324         return businessError;
325     }
326 
327     napi_value code = nullptr;
328     napi_value msg = nullptr;
329     NAPI_CALL(env, napi_create_int32(env, SERVICE_EXCEPTION, &code));
330     NAPI_CALL(env, napi_create_string_utf8(env, msgString.value().c_str(), NAPI_AUTO_LENGTH, &msg));
331     napi_create_error(env, nullptr, msg, &businessError);
332     napi_set_named_property(env, businessError, "code", code);
333     napi_set_named_property(env, businessError, "message", msg);
334     return businessError;
335 }
336 
ConvertToJsDeviceId(const napi_env & env,uint64_t deviceId)337 static napi_value ConvertToJsDeviceId(const napi_env &env, uint64_t deviceId)
338 {
339     napi_value result;
340     if (deviceId > MAX_JS_NUMBER) {
341         NAPI_CALL(env, napi_create_bigint_uint64(env, deviceId, &result));
342     } else {
343         NAPI_CALL(env, napi_create_int64(env, deviceId, &result));
344     }
345     return result;
346 }
347 
ThrowErr(const napi_env & env,const int32_t errCode,const std::string & printMsg)348 void ThrowErr(const napi_env &env, const int32_t errCode, const std::string &printMsg)
349 {
350     EDM_LOGE(MODULE_DEV_MGR, "message: %{public}s, code: %{public}d", printMsg.c_str(), errCode);
351     auto msg = GetNapiError(errCode);
352     if (!msg) {
353         EDM_LOGE(MODULE_DEV_MGR, "errCode: %{public}d is invalid", errCode);
354         return;
355     }
356     napi_handle_scope scope = nullptr;
357     napi_open_handle_scope(env, &scope);
358     napi_value error = CreateBusinessError(env, errCode, msg.value());
359     napi_throw(env, error);
360     napi_close_handle_scope(env, scope);
361 }
362 
ConvertDeviceToJsDevice(napi_env & env,std::shared_ptr<DeviceData> device)363 static napi_value ConvertDeviceToJsDevice(napi_env& env, std::shared_ptr<DeviceData> device)
364 {
365     napi_value object;
366     napi_value value;
367     NAPI_CALL(env, napi_create_object(env, &object));
368     NAPI_CALL(env, napi_create_int32(env, device->busType, &value));
369     NAPI_CALL(env, napi_set_named_property(env, object, "busType", value));
370     value = ConvertToJsDeviceId(env, device->deviceId);
371     NAPI_CALL(env, napi_set_named_property(env, object, "deviceId", value));
372     if (device->busType == BusType::BUS_TYPE_USB) {
373         std::shared_ptr<USBDevice> usb = std::static_pointer_cast<USBDevice>(device);
374         NAPI_CALL(env, napi_create_uint32(env, usb->vendorId, &value));
375         NAPI_CALL(env, napi_set_named_property(env, object, "vendorId", value));
376         NAPI_CALL(env, napi_create_uint32(env, usb->productId, &value));
377         NAPI_CALL(env, napi_set_named_property(env, object, "productId", value));
378     }
379 
380     return object;
381 }
382 
QueryDevices(napi_env env,napi_callback_info info)383 static napi_value QueryDevices(napi_env env, napi_callback_info info)
384 {
385     if (!ExtPermissionManager::GetInstance().HasPermission(PERMISSION_NAME)) {
386         ThrowErr(env, PERMISSION_DENIED, "queryDevices: no permission");
387         return nullptr;
388     }
389     EDM_LOGI(MODULE_DEV_MGR, "queryDevices start");
390     size_t argc = PARAM_COUNT_1;
391     napi_value argv[PARAM_COUNT_1] = {nullptr};
392     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
393 
394     int32_t busType = BusType::BUS_TYPE_USB;
395     if (argc > 0 && IsMatchType(env, argv[0], napi_number)) {
396         NAPI_CALL(env, napi_get_value_int32(env, argv[0], &busType));
397         EDM_LOGI(MODULE_DEV_MGR, "bus type is %{public}d", busType);
398     }
399 
400     std::vector<std::shared_ptr<DeviceData>> devices;
401     if (g_edmClient.QueryDevice(busType, devices) != UsbErrCode::EDM_OK) {
402         ThrowErr(env, SERVICE_EXCEPTION, "Query device service fail");
403         return nullptr;
404     }
405 
406     napi_value resultArray;
407     NAPI_CALL(env, napi_create_array(env, &resultArray));
408     for (size_t index = 0; index < devices.size(); index++) {
409         napi_value element = ConvertDeviceToJsDevice(env, devices[index]);
410         NAPI_CALL(env, napi_set_element(env, resultArray, index, element));
411     }
412     EDM_LOGI(MODULE_DEV_MGR, "query device finish");
413 
414     return resultArray;
415 }
416 
ParseDeviceId(const napi_env & env,const napi_value & value,uint64_t * deviceId)417 static bool ParseDeviceId(const napi_env& env, const napi_value& value, uint64_t* deviceId)
418 {
419     napi_valuetype type;
420     NAPI_CALL_BASE(env, napi_typeof(env, value, &type), false);
421     if (type == napi_bigint) {
422         bool lossless;
423         NAPI_CALL_BASE(env, napi_get_value_bigint_uint64(env, value, deviceId, &lossless), false);
424     } else if (type == napi_number) {
425         int64_t temp;
426         NAPI_CALL_BASE(env, napi_get_value_int64(env, value, &temp), false);
427         *deviceId = static_cast<uint64_t>(temp);
428     } else {
429         return false;
430     }
431     return true;
432 }
433 
BindDevice(napi_env env,napi_callback_info info)434 static napi_value BindDevice(napi_env env, napi_callback_info info)
435 {
436     if (!ExtPermissionManager::GetInstance().HasPermission(PERMISSION_NAME)) {
437         ThrowErr(env, PERMISSION_DENIED, "bindDevice: no permission");
438         return nullptr;
439     }
440     size_t argc = PARAM_COUNT_3;
441     napi_value argv[PARAM_COUNT_3] = {nullptr};
442     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
443     if (argc < PARAM_COUNT_2) {
444         ThrowErr(env, PARAMETER_ERROR, "bindDevice parameter count not match");
445         return nullptr;
446     }
447 
448     uint64_t deviceId;
449     if (!ParseDeviceId(env, argv[0], &deviceId)) {
450         ThrowErr(env, PARAMETER_ERROR, "deviceid type error");
451         return nullptr;
452     }
453     EDM_LOGI(MODULE_DEV_MGR, "Enter bindDevice:%{public}016" PRIX64, deviceId);
454 
455     if (!IsMatchType(env, argv[1], napi_function)) {
456         ThrowErr(env, PARAMETER_ERROR, "onDisconnect param is error");
457         return nullptr;
458     }
459 
460     std::lock_guard<std::mutex> mapLock(mapMutex);
461     if (g_edmClient.BindDevice(deviceId, g_edmCallback) != UsbErrCode::EDM_OK) {
462         ThrowErr(env, SERVICE_EXCEPTION, "bindDevice service failed");
463         return nullptr;
464     }
465 
466     sptr<AsyncData> data = new (std::nothrow) AsyncData {};
467     if (data == nullptr) {
468         ThrowErr(env, PARAMETER_ERROR, "malloc callback data fail");
469         return nullptr;
470     }
471     data->env = env;
472     data->deviceId = deviceId;
473     NAPI_CALL(env, napi_create_reference(env, argv[1], 1, &data->onDisconnect));
474     napi_value promise = nullptr;
475     if (argc > PARAM_COUNT_2 && IsMatchType(env, argv[PARAM_COUNT_2], napi_function)) {
476         NAPI_CALL(env, napi_create_reference(env, argv[PARAM_COUNT_2], 1, &data->bindCallback));
477     } else {
478         NAPI_CALL(env, napi_create_promise(env, &data->bindDeferred, &promise));
479     }
480     g_callbackMap[data->deviceId] = data;
481 
482     return promise;
483 }
484 
UnbindDevice(napi_env env,napi_callback_info info)485 static napi_value UnbindDevice(napi_env env, napi_callback_info info)
486 {
487     if (!ExtPermissionManager::GetInstance().HasPermission(PERMISSION_NAME)) {
488         ThrowErr(env, PERMISSION_DENIED, "unbindDevice: no permission");
489         return nullptr;
490     }
491     size_t argc = PARAM_COUNT_2;
492     napi_value argv[PARAM_COUNT_2] = {nullptr};
493     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
494     if (argc < PARAM_COUNT_1) {
495         ThrowErr(env, PARAMETER_ERROR, "Param count error");
496         return nullptr;
497     }
498 
499     uint64_t deviceId;
500     if (!ParseDeviceId(env, argv[0], &deviceId)) {
501         ThrowErr(env, PARAMETER_ERROR, "deviceid type error");
502         return nullptr;
503     }
504     EDM_LOGI(MODULE_DEV_MGR, "Enter unbindDevice:%{public}016" PRIX64, deviceId);
505 
506     std::lock_guard<std::mutex> mapLock(mapMutex);
507     if (g_callbackMap.count(deviceId) == 0) {
508         ThrowErr(env, SERVICE_EXCEPTION, "unbind map is null");
509         return nullptr;
510     }
511 
512     if (g_edmClient.UnBindDevice(deviceId) != UsbErrCode::EDM_OK) {
513         ThrowErr(env, SERVICE_EXCEPTION, "unbindDevice service failed");
514         return nullptr;
515     }
516     auto data = g_callbackMap[deviceId];
517     napi_value promise = nullptr;
518     if (argc > PARAM_COUNT_1 && IsMatchType(env, argv[1], napi_function)) {
519         NAPI_CALL(env, napi_create_reference(env, argv[1], 1, &data->unbindCallback));
520     } else {
521         NAPI_CALL(env, napi_create_promise(env, &data->unbindDeferred, &promise));
522     }
523 
524     return promise;
525 }
526 
EnumBusTypeConstructor(napi_env env,napi_callback_info info)527 static napi_value EnumBusTypeConstructor(napi_env env, napi_callback_info info)
528 {
529     napi_value thisArg = nullptr;
530     void* data = nullptr;
531 
532     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data));
533     return thisArg;
534 }
535 
CreateEnumBusType(napi_env env,napi_value exports)536 static void CreateEnumBusType(napi_env env, napi_value exports)
537 {
538     napi_value usb = nullptr;
539     napi_create_int32(env, 1, &usb);
540 
541     napi_property_descriptor desc[] = {
542         DECLARE_NAPI_STATIC_PROPERTY("USB", usb),
543     };
544 
545     napi_value result = nullptr;
546     napi_define_class(env, "BusType", NAPI_AUTO_LENGTH, EnumBusTypeConstructor, nullptr,
547         sizeof(desc) / sizeof(*desc), desc, &result);
548     napi_set_named_property(env, exports, "BusType", result);
549 }
550 
551 EXTERN_C_START
552 /*
553  * function for module exports
554  */
ExtDeviceManagerInit(napi_env env,napi_value exports)555 static napi_value ExtDeviceManagerInit(napi_env env, napi_value exports)
556 {
557     napi_property_descriptor desc[] = {
558         DECLARE_NAPI_FUNCTION("queryDevices", QueryDevices),
559         DECLARE_NAPI_FUNCTION("bindDevice", BindDevice),
560         DECLARE_NAPI_FUNCTION("bindDeviceDriver", BindDevice),
561         DECLARE_NAPI_FUNCTION("unbindDevice", UnbindDevice),
562     };
563     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
564 
565     CreateEnumBusType(env, exports);
566 
567     return exports;
568 }
569 EXTERN_C_END
570 
571 /*
572  * Module definition
573  */
574 static napi_module g_moduleManager = {
575     .nm_version = 1,
576     .nm_flags = 0,
577     .nm_filename = nullptr,
578     .nm_register_func = ExtDeviceManagerInit,
579     .nm_modname = "driver.deviceManager",
580     .nm_priv = nullptr,
581     .reserved = {nullptr}
582 };
583 
584 /*
585  * Module registration
586  */
RegisterModule(void)587 extern "C" __attribute__((constructor)) void RegisterModule(void)
588 {
589     napi_module_register(&g_moduleManager);
590 }
591 }
592 }