• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "devicestatus_napi.h"
17 
18 #include <js_native_api.h>
19 
20 #include "napi/native_api.h"
21 #include "napi/native_node_api.h"
22 
23 #include "devicestatus_client.h"
24 #include "devicestatus_common.h"
25 
26 using namespace OHOS;
27 using namespace OHOS::Msdp;
28 namespace {
29 constexpr size_t ARG_0 = 0;
30 constexpr size_t ARG_1 = 1;
31 constexpr size_t ARG_2 = 2;
32 constexpr size_t ARG_3 = 3;
33 constexpr size_t ARG_4 = 4;
34 constexpr int32_t NAPI_BUF_LENGTH  = 256;
35 static const std::vector<std::string> vecDeviceStatusValue {
36     "VALUE_ENTER", "VALUE_EXIT"
37 };
38 thread_local DeviceStatusNapi *g_obj = nullptr;
39 } // namespace
40 std::map<int32_t, sptr<IdevicestatusCallback>> DeviceStatusNapi::callbackMap_;
41 napi_ref DeviceStatusNapi::devicestatusValueRef_ = nullptr;
42 
43 struct ResponseEntity {
44     DevicestatusDataUtils::DevicestatusValue value;
45 };
46 
OnDevicestatusChanged(const DevicestatusDataUtils::DevicestatusData & devicestatusData)47 void DeviceStatusCallback::OnDevicestatusChanged(const DevicestatusDataUtils::DevicestatusData& devicestatusData)
48 {
49     DEV_HILOGD(JS_NAPI, "OnDevicestatusChanged enter");
50     std::lock_guard<std::mutex> guard(mutex_);
51     uv_loop_s *loop = nullptr;
52     napi_get_uv_event_loop(env_, &loop);
53     if (loop == nullptr) {
54         DEV_HILOGE(JS_NAPI, "loop is nullptr");
55         return;
56     }
57     uv_work_t *work = new (std::nothrow) uv_work_t;
58     if (work == nullptr) {
59         DEV_HILOGE(JS_NAPI, "work is nullptr");
60         return;
61     }
62     DEV_HILOGD(JS_NAPI, "devicestatusData.type:%{public}d, devicestatusData.value:%{public}d",
63         devicestatusData.type, devicestatusData.value);
64     data_ = devicestatusData;
65     work->data = static_cast<void *>(&data_);
66     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, EmitOnEvent);
67     if (ret != 0) {
68         DEV_HILOGE(JS_NAPI, "Failed to execute work queue");
69     }
70 }
71 
EmitOnEvent(uv_work_t * work,int status)72 void DeviceStatusCallback::EmitOnEvent(uv_work_t *work, int status)
73 {
74     DevicestatusDataUtils::DevicestatusData* data = static_cast<DevicestatusDataUtils::DevicestatusData*>(work->data);
75     delete work;
76     if (data == nullptr) {
77         DEV_HILOGE(JS_NAPI, "work->data is nullptr");
78         return;
79     }
80     DeviceStatusNapi* deviceStatusNapi = DeviceStatusNapi::GetDeviceStatusNapi();
81     if (deviceStatusNapi == nullptr) {
82         DEV_HILOGE(JS_NAPI, "deviceStatusNapi is nullptr");
83         return;
84     }
85 
86     int32_t type = static_cast<int32_t>(data->type);
87     int32_t value = static_cast<int32_t>(data->value);
88     DEV_HILOGD(JS_NAPI, "type:%{public}d, value:%{public}d", type, value);
89     deviceStatusNapi->OnDeviceStatusChangedDone(type, value, false);
90 }
91 
GetDeviceStatusNapi()92 DeviceStatusNapi* DeviceStatusNapi::GetDeviceStatusNapi()
93 {
94     DEV_HILOGD(JS_NAPI, "Enter");
95     return g_obj;
96 }
97 
DeviceStatusNapi(napi_env env)98 DeviceStatusNapi::DeviceStatusNapi(napi_env env) : DeviceStatusEvent(env)
99 {
100     env_ = env;
101     callbackRef_ = nullptr;
102     devicestatusValueRef_ = nullptr;
103 }
104 
~DeviceStatusNapi()105 DeviceStatusNapi::~DeviceStatusNapi()
106 {
107     if (callbackRef_ != nullptr) {
108         napi_delete_reference(env_, callbackRef_);
109     }
110     if (devicestatusValueRef_ != nullptr) {
111         napi_delete_reference(env_, devicestatusValueRef_);
112     }
113     if (g_obj != nullptr) {
114         delete g_obj;
115         g_obj = nullptr;
116     }
117 }
118 
OnDeviceStatusChangedDone(int32_t type,int32_t value,bool isOnce)119 void DeviceStatusNapi::OnDeviceStatusChangedDone(int32_t type, int32_t value, bool isOnce)
120 {
121     DEV_HILOGD(JS_NAPI, "Enter, value:%{public}d", value);
122     OnEvent(type, ARG_1, value, isOnce);
123     DEV_HILOGD(JS_NAPI, "Exit");
124 }
125 
ConvertTypeToInt(const std::string & type)126 int32_t DeviceStatusNapi::ConvertTypeToInt(const std::string &type)
127 {
128     if (type == "still") {
129         return DevicestatusDataUtils::DevicestatusType::TYPE_STILL;
130     } else if (type == "relativeStill") {
131         return DevicestatusDataUtils::DevicestatusType::TYPE_RELATIVE_STILL;
132     } else if (type == "carBluetooth") {
133         return DevicestatusDataUtils::DevicestatusType::TYPE_CAR_BLUETOOTH;
134     } else {
135         return DevicestatusDataUtils::DevicestatusType::TYPE_INVALID;
136     }
137 }
138 
CheckArguments(napi_env env,napi_callback_info info)139 bool DeviceStatusNapi::CheckArguments(napi_env env, napi_callback_info info)
140 {
141     DEV_HILOGD(JS_NAPI, "Enter");
142     int arr[ARG_4] = {};
143     size_t argc = ARG_4;
144     napi_value args[ARG_4] = {};
145     napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
146     if (status != napi_ok) {
147         DEV_HILOGE(JS_NAPI, "Failed to get_cb_info");
148         return false;
149     }
150     for (size_t i = 0; i < ARG_4; i++) {
151         napi_valuetype valueType = napi_undefined;
152         status = napi_typeof(env, args[i], &valueType);
153         if (status != napi_ok) {
154             DEV_HILOGE(JS_NAPI, "Failed to get valueType");
155             return false;
156         }
157         DEV_HILOGD(JS_NAPI, "valueType:%{public}d", valueType);
158         arr[i] = valueType;
159     }
160     if (arr[ARG_0] != napi_string || arr[ARG_1] != napi_number || arr[ARG_2] != napi_number ||
161         arr[ARG_3] != napi_function) {
162         DEV_HILOGE(JS_NAPI, "Failed to get arguements");
163         return false;
164     }
165     DEV_HILOGD(JS_NAPI, "Exit");
166     return true;
167 }
168 
CheckUnsubArguments(napi_env env,napi_callback_info info)169 bool DeviceStatusNapi::CheckUnsubArguments(napi_env env, napi_callback_info info)
170 {
171     DEV_HILOGD(JS_NAPI, "Enter");
172     int arr[ARG_3] = {};
173     size_t argc = ARG_3;
174     napi_value args[ARG_3] = {};
175     napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
176     if (status != napi_ok) {
177         DEV_HILOGE(JS_NAPI, "Failed to get_cb_info");
178         return false;
179     }
180     for (size_t i = 0; i < ARG_3; i++) {
181         napi_valuetype valueType = napi_undefined;
182         status = napi_typeof(env, args[i], &valueType);
183         if (status != napi_ok) {
184             DEV_HILOGE(JS_NAPI, "Failed to get valueType");
185             return false;
186         }
187         DEV_HILOGD(JS_NAPI, "valueType:%{public}d", valueType);
188         arr[i] = valueType;
189     }
190     if (arr[ARG_0] != napi_string || arr[ARG_1] != napi_number || arr[ARG_2] != napi_function) {
191         DEV_HILOGE(JS_NAPI, "Failed to get arguements");
192         return false;
193     }
194     DEV_HILOGD(JS_NAPI, "Exit");
195     return true;
196 }
197 
CheckGetArguments(napi_env env,napi_callback_info info)198 bool DeviceStatusNapi::CheckGetArguments(napi_env env, napi_callback_info info)
199 {
200     DEV_HILOGD(JS_NAPI, "Enter");
201     int arr[ARG_2] = {};
202     size_t argc = ARG_2;
203     napi_value args[ARG_2] = {};
204     napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
205     if (status != napi_ok) {
206         DEV_HILOGE(JS_NAPI, "Failed to get_cb_info");
207         return false;
208     }
209     for (size_t i = 0; i < ARG_2; i++) {
210         napi_valuetype valueType = napi_undefined;
211         status = napi_typeof(env, args[i], &valueType);
212         if (status != napi_ok) {
213             DEV_HILOGE(JS_NAPI, "Failed to get valueType");
214             return false;
215         }
216         DEV_HILOGD(JS_NAPI, "valueType:%{public}d", valueType);
217         arr[i] = valueType;
218     }
219     if (arr[ARG_0] != napi_string || arr[ARG_1] != napi_function) {
220         DEV_HILOGE(JS_NAPI, "Failed to get arguements");
221         return false;
222     }
223     DEV_HILOGD(JS_NAPI, "Exit");
224     return true;
225 }
226 
SubscribeDeviceStatusCallback(napi_env env,napi_callback_info info,napi_value * args,int32_t type,int32_t event,int32_t latency)227 napi_value DeviceStatusNapi::SubscribeDeviceStatusCallback(napi_env env, napi_callback_info info, napi_value *args,
228     int32_t type, int32_t event, int32_t latency)
229 {
230     if (g_obj == nullptr) {
231         g_obj = new (std::nothrow) DeviceStatusNapi(env);
232         if (g_obj == nullptr) {
233             DEV_HILOGE(JS_NAPI, "Failed to new g_obj");
234             return nullptr;
235         }
236         DEV_HILOGD(JS_NAPI, "Didn't find object, so created it");
237     }
238     napi_wrap(env, nullptr, reinterpret_cast<void *>(g_obj),
239         [](napi_env env, void *data, void *hint) {
240             (void)env;
241             (void)hint;
242             DeviceStatusNapi *devicestatus = static_cast<DeviceStatusNapi *>(data);
243             delete devicestatus;
244         },
245         nullptr, &(g_obj->callbackRef_));
246     if (!g_obj->On(type, args[ARG_3], false)) {
247         DEV_HILOGE(JS_NAPI, "type:%{public}d already exists", type);
248         return nullptr;
249     }
250     auto callbackIter = callbackMap_.find(type);
251     if (callbackIter != callbackMap_.end()) {
252         DEV_HILOGD(JS_NAPI, "Callback exists");
253         return nullptr;
254     }
255     sptr<IdevicestatusCallback> callback;
256     callback = new (std::nothrow) DeviceStatusCallback(env);
257     if (callback == nullptr) {
258         DEV_HILOGE(JS_NAPI, "callback is nullptr");
259         return nullptr;
260     }
261     DevicestatusClient::GetInstance().SubscribeCallback(DevicestatusDataUtils::DevicestatusType(type), callback);
262     auto ret = callbackMap_.insert(std::pair<int32_t, sptr<IdevicestatusCallback>>(type, callback));
263     if (!ret.second) {
264         DEV_HILOGE(JS_NAPI, "Failed to insert");
265         return nullptr;
266     }
267     DEV_HILOGD(JS_NAPI, "Exit");
268     return nullptr;
269 }
270 
SubscribeDeviceStatus(napi_env env,napi_callback_info info)271 napi_value DeviceStatusNapi::SubscribeDeviceStatus(napi_env env, napi_callback_info info)
272 {
273     DEV_HILOGD(JS_NAPI, "Subscribe Enter");
274     size_t argc = ARG_4;
275     napi_value args[ARG_4] = {};
276     napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
277     NAPI_ASSERT(env, (status == napi_ok) && (argc >= ARG_4), "Bad parameters");
278     if (!CheckArguments(env, info)) {
279         DEV_HILOGE(JS_NAPI, "Failed to get arguements");
280         return nullptr;
281     }
282     size_t modeLen = 0;
283     status = napi_get_value_string_utf8(env, args[ARG_0], nullptr, 0, &modeLen);
284     if (status != napi_ok) {
285         DEV_HILOGE(JS_NAPI, "Failed to get string item");
286         return nullptr;
287     }
288     char mode[NAPI_BUF_LENGTH] = {};
289     status = napi_get_value_string_utf8(env, args[ARG_0], mode, modeLen + 1, &modeLen);
290     if (status != napi_ok) {
291         DEV_HILOGE(JS_NAPI, "Failed to get string item");
292         return nullptr;
293     }
294     std::string typeMode = mode;
295     int32_t eventMode = 0;
296     status = napi_get_value_int32(env, args[ARG_1], &eventMode);
297     DEV_HILOGD(JS_NAPI, "mode:%{public}s,eventMode:%{public}d", typeMode.c_str(), eventMode);
298     if (status != napi_ok) {
299         DEV_HILOGE(JS_NAPI, "Failed to get event value item");
300         return nullptr;
301     }
302     int32_t latencyMode = 0;
303     status = napi_get_value_int32(env, args[ARG_2], &latencyMode);
304     if (status != napi_ok) {
305         DEV_HILOGE(JS_NAPI, "Failed to get latency value item");
306         return nullptr;
307     }
308     int32_t type = ConvertTypeToInt(typeMode);
309     int32_t event = eventMode;
310     int32_t latency = latencyMode;
311     DEV_HILOGD(JS_NAPI, "type:%{public}d, event:%{public}d, latency:%{public}d", type, event, latency);
312     NAPI_ASSERT(env, (type >= DevicestatusDataUtils::DevicestatusType::TYPE_STILL) &&
313         (type <= DevicestatusDataUtils::DevicestatusType::TYPE_LID_OPEN), "type is illegal");
314     return SubscribeDeviceStatusCallback(env, info, args, type, event, latency);
315 }
316 
UnsubscribeDeviceStatus(napi_env env,napi_callback_info info)317 napi_value DeviceStatusNapi::UnsubscribeDeviceStatus(napi_env env, napi_callback_info info)
318 {
319     DEV_HILOGD(JS_NAPI, "Enter");
320     if (g_obj == nullptr) {
321         DEV_HILOGE(JS_NAPI, "g_obj is nullptr");
322         return nullptr;
323     }
324     size_t argc = ARG_3;
325     napi_value args[ARG_3] = {};
326     napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
327     NAPI_ASSERT(env, (status == napi_ok) && (argc >= ARG_3), "Bad parameters");
328     if (!CheckUnsubArguments(env, info)) {
329         DEV_HILOGE(JS_NAPI, "Failed to get unsub arguements");
330         return nullptr;
331     }
332     size_t len;
333     status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &len);
334     if (status != napi_ok) {
335         DEV_HILOGE(JS_NAPI, "Failed to get string item");
336         return nullptr;
337     }
338     std::vector<char> typeBuf(len + 1);
339     status = napi_get_value_string_utf8(env, args[0], typeBuf.data(), len + 1, &len);
340     if (status != napi_ok) {
341         DEV_HILOGE(JS_NAPI, "Failed to get string item");
342         return nullptr;
343     }
344     int32_t type = ConvertTypeToInt(typeBuf.data());
345     NAPI_ASSERT(env, (type >= DevicestatusDataUtils::DevicestatusType::TYPE_STILL) &&
346         (type <= DevicestatusDataUtils::DevicestatusType::TYPE_LID_OPEN), "type is illegal");
347     int32_t eventMode = 0;
348     status = napi_get_value_int32(env, args[ARG_1], &eventMode);
349     if (status != napi_ok) {
350         DEV_HILOGE(JS_NAPI, "Failed to get int32 item");
351         return nullptr;
352     }
353     int32_t event = eventMode;
354     DEV_HILOGD(JS_NAPI, "type:%{public}d, event:%{public}d", type, event);
355     if (!g_obj->Off(type, args[ARG_2])) {
356         DEV_HILOGE(JS_NAPI, "Not ready to Unsubscribe for type:%{public}d", type);
357         return nullptr;
358     }
359     auto callbackIter = callbackMap_.find(type);
360     if (callbackIter != callbackMap_.end()) {
361         DevicestatusClient::GetInstance().UnSubscribeCallback(DevicestatusDataUtils::DevicestatusType(type),
362             callbackIter->second);
363         callbackMap_.erase(type);
364     } else {
365         NAPI_ASSERT(env, false, "No existed callback");
366         return nullptr;
367     }
368     DEV_HILOGD(JS_NAPI, "Exit");
369     return nullptr;
370 }
371 
GetDeviceStatus(napi_env env,napi_callback_info info)372 napi_value DeviceStatusNapi::GetDeviceStatus(napi_env env, napi_callback_info info)
373 {
374     DEV_HILOGD(JS_NAPI, "Enter");
375     size_t argc = ARG_2;
376     napi_value args[ARG_2] = {};
377     napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
378     NAPI_ASSERT(env, (status == napi_ok) && (argc >= ARG_2), "Bad parameters");
379     if (!CheckGetArguments(env, info)) {
380         DEV_HILOGE(JS_NAPI, "Failed to get once arguements");
381         return nullptr;
382     }
383     size_t len;
384     status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &len);
385     if (status != napi_ok) {
386         DEV_HILOGE(JS_NAPI, "Failed to get string item");
387         return nullptr;
388     }
389     std::vector<char> typeBuf(len + 1);
390     status = napi_get_value_string_utf8(env, args[0], typeBuf.data(), len + 1, &len);
391     if (status != napi_ok) {
392         DEV_HILOGE(JS_NAPI, "Failed to get string item");
393         return nullptr;
394     }
395     int32_t type = ConvertTypeToInt(typeBuf.data());
396     NAPI_ASSERT(env, (type >= DevicestatusDataUtils::DevicestatusType::TYPE_STILL) &&
397         (type <= DevicestatusDataUtils::DevicestatusType::TYPE_LID_OPEN), "type is illegal");
398     if (g_obj == nullptr) {
399         g_obj = new (std::nothrow) DeviceStatusNapi(env);
400         if (g_obj == nullptr) {
401             DEV_HILOGE(JS_NAPI, "Failed to new g_obj");
402             return nullptr;
403         }
404         napi_wrap(env, nullptr, reinterpret_cast<void *>(g_obj),
405             [](napi_env env, void *data, void *hint) {
406                 (void)env;
407                 (void)hint;
408                 DeviceStatusNapi *devicestatus = static_cast<DeviceStatusNapi *>(data);
409                 delete devicestatus;
410             },
411             nullptr, &(g_obj->callbackRef_));
412     }
413     if (!g_obj->On(type, args[ARG_1], true)) {
414         DEV_HILOGE(JS_NAPI, "type:%{public}d already exists", type);
415         return nullptr;
416     }
417     DevicestatusDataUtils::DevicestatusData devicestatusData =
418         DevicestatusClient::GetInstance().GetDevicestatusData(DevicestatusDataUtils::DevicestatusType(type));
419     g_obj->OnDeviceStatusChangedDone(devicestatusData.type, devicestatusData.value, true);
420     g_obj->OffOnce(devicestatusData.type, args[ARG_1]);
421     return nullptr;
422 }
423 
Init(napi_env env,napi_value exports)424 napi_value DeviceStatusNapi::Init(napi_env env, napi_value exports)
425 {
426     DEV_HILOGD(JS_NAPI, "Enter");
427     napi_property_descriptor desc[] = {
428         DECLARE_NAPI_FUNCTION("on", SubscribeDeviceStatus),
429         DECLARE_NAPI_FUNCTION("off", UnsubscribeDeviceStatus),
430         DECLARE_NAPI_FUNCTION("once", GetDeviceStatus),
431     };
432     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
433     DEV_HILOGD(JS_NAPI, "Exit");
434     return exports;
435 }
436 
437 EXTERN_C_START
438 /*
439  * function for module exports
440  */
DeviceStatusInit(napi_env env,napi_value exports)441 static napi_value DeviceStatusInit(napi_env env, napi_value exports)
442 {
443     DEV_HILOGD(JS_NAPI, "Enter");
444     napi_value ret = DeviceStatusNapi::Init(env, exports);
445     DEV_HILOGD(JS_NAPI, "Exit");
446     return ret;
447 }
448 EXTERN_C_END
449 
450 /*
451  * Module definition
452  */
453 static napi_module g_module = {
454     .nm_version = 1,
455     .nm_flags = 0,
456     .nm_filename = "stationary",
457     .nm_register_func = DeviceStatusInit,
458     .nm_modname = "stationary",
459     .nm_priv = (static_cast<void *>(0)),
460     .reserved = {0}
461 };
462 
463 /*
464  * Module registration
465  */
RegisterModule(void)466 extern "C" __attribute__((constructor)) void RegisterModule(void)
467 {
468     napi_module_register(&g_module);
469 }
470