• 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 "js_cooperate_context.h"
17 
18 #include "devicestatus_define.h"
19 #include "napi_constants.h"
20 #include "util_napi_error.h"
21 
22 namespace OHOS {
23 namespace Msdp {
24 namespace DeviceStatus {
25 namespace {
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "JsCooperateContext" };
27 const char* g_coordinationClass { "Coordination_class" };
28 const char* g_coordination { "Coordination" };
29 inline constexpr std::string_view GET_VALUE_BOOL { "napi_get_value_bool" };
30 inline constexpr std::string_view GET_VALUE_INT32 { "napi_get_value_int32" };
31 inline constexpr std::string_view GET_VALUE_STRING_UTF8 { "napi_get_value_string_utf8" };
32 inline constexpr size_t MAX_STRING_LEN { 1024 };
33 } // namespace
34 
JsCooperateContext()35 JsCooperateContext::JsCooperateContext()
36     : mgr_(std::make_shared<JsCooperateManager>()) {}
37 
~JsCooperateContext()38 JsCooperateContext::~JsCooperateContext()
39 {
40     std::lock_guard<std::mutex> guard(mutex_);
41     auto jsCooperateManager = mgr_;
42     mgr_.reset();
43     if (jsCooperateManager != nullptr) {
44         jsCooperateManager->ResetEnv();
45     }
46 }
47 
Export(napi_env env,napi_value exports)48 napi_value JsCooperateContext::Export(napi_env env, napi_value exports)
49 {
50     CALL_INFO_TRACE;
51     auto instance = CreateInstance(env);
52     CHKPP(instance);
53     DeclareDeviceCoordinationInterface(env, exports);
54     DeclareDeviceCoordinationData(env, exports);
55     return exports;
56 }
57 
Enable(napi_env env,napi_callback_info info)58 napi_value JsCooperateContext::Enable(napi_env env, napi_callback_info info)
59 {
60     CALL_INFO_TRACE;
61     size_t argc = TWO_PARAM;
62     napi_value argv[TWO_PARAM] = { nullptr };
63     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
64 
65     if (argc == ZERO_PARAM) {
66         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Wrong number of parameters");
67         return nullptr;
68     }
69     if (!UtilNapi::TypeOf(env, argv[ZERO_PARAM], napi_boolean)) {
70         THROWERR(env, COMMON_PARAMETER_ERROR, "enable", "boolean");
71         return nullptr;
72     }
73     bool enable = false;
74     CHKRP(napi_get_value_bool(env, argv[ZERO_PARAM], &enable), GET_VALUE_BOOL);
75 
76     JsCooperateContext *jsDev = JsCooperateContext::GetInstance(env);
77     CHKPP(jsDev);
78     auto jsCooperateManager = jsDev->GetJsCoordinationMgr();
79     CHKPP(jsCooperateManager);
80     if (argc == ONE_PARAM) {
81         return jsCooperateManager->Enable(env, enable);
82     }
83     if (!UtilNapi::TypeOf(env, argv[ONE_PARAM], napi_function)) {
84         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
85         return nullptr;
86     }
87     return jsCooperateManager->Enable(env, enable, argv[ONE_PARAM]);
88 }
89 
Start(napi_env env,napi_callback_info info)90 napi_value JsCooperateContext::Start(napi_env env, napi_callback_info info)
91 {
92     CALL_INFO_TRACE;
93     size_t argc = THREE_PARAM;
94     napi_value argv[THREE_PARAM] = { nullptr };
95     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
96 
97     if (argc < TWO_PARAM) {
98         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Wrong number of parameters");
99         return nullptr;
100     }
101     if (!UtilNapi::TypeOf(env, argv[ZERO_PARAM], napi_string)) {
102         THROWERR(env, COMMON_PARAMETER_ERROR, "remoteNetworkDescriptor", "string");
103         return nullptr;
104     }
105     if (!UtilNapi::TypeOf(env, argv[ONE_PARAM], napi_number)) {
106         THROWERR(env, COMMON_PARAMETER_ERROR, "startDeviceId", "number");
107         return nullptr;
108     }
109     char remoteNetworkDescriptor[MAX_STRING_LEN] = { 0 };
110     int32_t startDeviceId = ZERO_PARAM;
111     size_t length = ZERO_PARAM;
112     CHKRP(napi_get_value_string_utf8(env, argv[ZERO_PARAM], remoteNetworkDescriptor,
113         sizeof(remoteNetworkDescriptor), &length), GET_VALUE_STRING_UTF8);
114     CHKRP(napi_get_value_int32(env, argv[ONE_PARAM], &startDeviceId), GET_VALUE_INT32);
115 
116     JsCooperateContext *jsDev = JsCooperateContext::GetInstance(env);
117     CHKPP(jsDev);
118     auto jsCooperateManager = jsDev->GetJsCoordinationMgr();
119     CHKPP(jsCooperateManager);
120     if (argc == TWO_PARAM) {
121         return jsCooperateManager->Start(env, remoteNetworkDescriptor, startDeviceId);
122     }
123     if (!UtilNapi::TypeOf(env, argv[TWO_PARAM], napi_function)) {
124         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
125         return nullptr;
126     }
127     return jsCooperateManager->Start(env, std::string(remoteNetworkDescriptor), startDeviceId, argv[TWO_PARAM]);
128 }
129 
Stop(napi_env env,napi_callback_info info)130 napi_value JsCooperateContext::Stop(napi_env env, napi_callback_info info)
131 {
132     CALL_INFO_TRACE;
133     size_t argc = ONE_PARAM;
134     napi_value argv[ONE_PARAM] = { nullptr };
135     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
136 
137     JsCooperateContext *jsDev = JsCooperateContext::GetInstance(env);
138     CHKPP(jsDev);
139     auto jsCooperateManager = jsDev->GetJsCoordinationMgr();
140     CHKPP(jsCooperateManager);
141     if (argc == ZERO_PARAM) {
142         return jsCooperateManager->Stop(env);
143     }
144     if (!UtilNapi::TypeOf(env, argv[ZERO_PARAM], napi_function)) {
145         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
146         return nullptr;
147     }
148     return jsCooperateManager->Stop(env, argv[ZERO_PARAM]);
149 }
150 
GetState(napi_env env,napi_callback_info info)151 napi_value JsCooperateContext::GetState(napi_env env, napi_callback_info info)
152 {
153     CALL_INFO_TRACE;
154     size_t argc = TWO_PARAM;
155     napi_value argv[TWO_PARAM] = { nullptr };
156     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
157 
158     if (argc == ZERO_PARAM) {
159         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Incorrect parameter count");
160         return nullptr;
161     }
162     if (!UtilNapi::TypeOf(env, argv[ZERO_PARAM], napi_string)) {
163         THROWERR(env, COMMON_PARAMETER_ERROR, "deviceDescriptor", "string");
164         return nullptr;
165     }
166     char deviceDescriptor[MAX_STRING_LEN] = { ZERO_PARAM };
167     size_t length = ZERO_PARAM;
168     CHKRP(napi_get_value_string_utf8(env, argv[ZERO_PARAM], deviceDescriptor,
169         sizeof(deviceDescriptor), &length), GET_VALUE_STRING_UTF8);
170     std::string deviceDescriptorTmp = deviceDescriptor;
171 
172     JsCooperateContext *jsDev = JsCooperateContext::GetInstance(env);
173     CHKPP(jsDev);
174     auto jsCooperateManager = jsDev->GetJsCoordinationMgr();
175     CHKPP(jsCooperateManager);
176     if (argc == ONE_PARAM) {
177         return jsCooperateManager->GetState(env, deviceDescriptorTmp);
178     }
179     if (!UtilNapi::TypeOf(env, argv[ONE_PARAM], napi_function)) {
180         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
181         return nullptr;
182     }
183     return jsCooperateManager->GetState(env, deviceDescriptorTmp, argv[ONE_PARAM]);
184 }
185 
On(napi_env env,napi_callback_info info)186 napi_value JsCooperateContext::On(napi_env env, napi_callback_info info)
187 {
188     CALL_INFO_TRACE;
189     napi_value argv[TWO_PARAM] = { nullptr };
190     size_t argc = TWO_PARAM;
191     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
192     if (argc == ZERO_PARAM) {
193         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Mismatched parameter count");
194         return nullptr;
195     }
196 
197     if (!UtilNapi::TypeOf(env, argv[ZERO_PARAM], napi_string)) {
198         THROWERR(env, COMMON_PARAMETER_ERROR, "type", "string");
199         return nullptr;
200     }
201     char type[MAX_STRING_LEN] = { 0 };
202     size_t length = ZERO_PARAM;
203     CHKRP(napi_get_value_string_utf8(env, argv[ZERO_PARAM], type, sizeof(type), &length), GET_VALUE_STRING_UTF8);
204     if (std::strcmp(type, "cooperation") != ZERO_PARAM) {
205         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Type must be cooperation");
206         return nullptr;
207     }
208     JsCooperateContext *jsDev = JsCooperateContext::GetInstance(env);
209     CHKPP(jsDev);
210     auto jsCooperateManager = jsDev->GetJsCoordinationMgr();
211     CHKPP(jsCooperateManager);
212     if (!UtilNapi::TypeOf(env, argv[ONE_PARAM], napi_function)) {
213         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
214         return nullptr;
215     }
216     jsCooperateManager->RegisterListener(env, type, argv[ONE_PARAM]);
217     return nullptr;
218 }
219 
Off(napi_env env,napi_callback_info info)220 napi_value JsCooperateContext::Off(napi_env env, napi_callback_info info)
221 {
222     CALL_INFO_TRACE;
223     size_t argc = TWO_PARAM;
224     napi_value argv[TWO_PARAM] = { nullptr };
225     CHKRP(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
226 
227     if (argc == ZERO_PARAM) {
228         THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Wrong number of parameters");
229         return nullptr;
230     }
231     if (!UtilNapi::TypeOf(env, argv[ZERO_PARAM], napi_string)) {
232         THROWERR(env, COMMON_PARAMETER_ERROR, "type", "string");
233         return nullptr;
234     }
235     char type[MAX_STRING_LEN] = { 0 };
236     size_t length = ZERO_PARAM;
237     CHKRP(napi_get_value_string_utf8(env, argv[ZERO_PARAM], type, sizeof(type), &length), GET_VALUE_STRING_UTF8);
238     std::string typeTmp = type;
239 
240     JsCooperateContext *jsDev = JsCooperateContext::GetInstance(env);
241     CHKPP(jsDev);
242     auto jsCooperateManager = jsDev->GetJsCoordinationMgr();
243     CHKPP(jsCooperateManager);
244     if (argc == ONE_PARAM) {
245         jsCooperateManager->UnregisterListener(env, typeTmp);
246         return nullptr;
247     }
248     if (!UtilNapi::TypeOf(env, argv[ONE_PARAM], napi_function)) {
249         THROWERR(env, COMMON_PARAMETER_ERROR, "callback", "function");
250         return nullptr;
251     }
252     jsCooperateManager->UnregisterListener(env, typeTmp, argv[ONE_PARAM]);
253     return nullptr;
254 }
255 
GetJsCoordinationMgr()256 std::shared_ptr<JsCooperateManager> JsCooperateContext::GetJsCoordinationMgr()
257 {
258     std::lock_guard<std::mutex> guard(mutex_);
259     return mgr_;
260 }
261 
CreateInstance(napi_env env)262 napi_value JsCooperateContext::CreateInstance(napi_env env)
263 {
264     CALL_INFO_TRACE;
265     napi_value global = nullptr;
266     CHKRP(napi_get_global(env, &global), GET_GLOBAL);
267 
268     constexpr char className[] = "JsCooperateContext";
269     napi_value jsClass = nullptr;
270     napi_property_descriptor desc[] = {};
271     napi_status status = napi_define_class(env, className, sizeof(className),
272         JsCooperateContext::JsConstructor, nullptr, sizeof(desc) / sizeof(desc[ZERO_PARAM]), nullptr, &jsClass);
273     CHKRP(status, DEFINE_CLASS);
274 
275     status = napi_set_named_property(env, global, g_coordinationClass, jsClass);
276     CHKRP(status, SET_NAMED_PROPERTY);
277 
278     napi_value jsInstance = nullptr;
279     CHKRP(napi_new_instance(env, jsClass, ZERO_PARAM, nullptr, &jsInstance), NEW_INSTANCE);
280     CHKRP(napi_set_named_property(env, global, g_coordination, jsInstance),
281         SET_NAMED_PROPERTY);
282 
283     JsCooperateContext *jsContext = nullptr;
284     CHKRP(napi_unwrap(env, jsInstance, reinterpret_cast<void**>(&jsContext)), UNWRAP);
285     CHKPP(jsContext);
286     CHKRP(napi_create_reference(env, jsInstance, ONE_PARAM, &(jsContext->contextRef_)), CREATE_REFERENCE);
287 
288     uint32_t refCount = ZERO_PARAM;
289     status = napi_reference_ref(env, jsContext->contextRef_, &refCount);
290     if (status != napi_ok) {
291         FI_HILOGE("ref is nullptr");
292         napi_delete_reference(env, jsContext->contextRef_);
293         return nullptr;
294     }
295     return jsInstance;
296 }
297 
JsConstructor(napi_env env,napi_callback_info info)298 napi_value JsCooperateContext::JsConstructor(napi_env env, napi_callback_info info)
299 {
300     CALL_INFO_TRACE;
301     napi_value thisVar = nullptr;
302     void *data = nullptr;
303     CHKRP(napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data), GET_CB_INFO);
304 
305     JsCooperateContext *jsContext = new (std::nothrow) JsCooperateContext();
306     CHKPP(jsContext);
307     napi_status status = napi_wrap(env, thisVar, jsContext, [](napi_env env, void *data, void *hin) {
308         FI_HILOGI("Jsvm ends");
309         JsCooperateContext *context = static_cast<JsCooperateContext*>(data);
310         delete context;
311     }, nullptr, nullptr);
312     if (status != napi_ok) {
313         FI_HILOGE("%{public}s failed", std::string(WRAP).c_str());
314         delete jsContext;
315         auto infoTemp = std::string(__FUNCTION__) + ": " + std::string(WRAP) + " failed";
316         napi_throw_error(env, nullptr, infoTemp.c_str());
317         return nullptr;
318     }
319     return thisVar;
320 }
321 
GetInstance(napi_env env)322 JsCooperateContext *JsCooperateContext::GetInstance(napi_env env)
323 {
324     CALL_INFO_TRACE;
325     napi_value global = nullptr;
326     CHKRP(napi_get_global(env, &global), GET_GLOBAL);
327 
328     bool result = false;
329     CHKRP(napi_has_named_property(env, global, g_coordination, &result), HAS_NAMED_PROPERTY);
330     if (!result) {
331         FI_HILOGE("Coordination was not found");
332         return nullptr;
333     }
334 
335     napi_handle_scope scope = nullptr;
336     napi_open_handle_scope(env, &scope);
337     CHKPP(scope);
338     napi_value object = nullptr;
339     CHKRP_SCOPE(env, napi_get_named_property(env, global, g_coordination, &object), GET_NAMED_PROPERTY, scope);
340     if (object == nullptr) {
341         napi_close_handle_scope(env, scope);
342         FI_HILOGE("object is nullptr");
343         return nullptr;
344     }
345 
346     JsCooperateContext *instance = nullptr;
347     CHKRP_SCOPE(env, napi_unwrap(env, object, reinterpret_cast<void**>(&instance)), UNWRAP, scope);
348     if (instance == nullptr) {
349         napi_close_handle_scope(env, scope);
350         FI_HILOGE("instance is nullptr");
351         return nullptr;
352     }
353     napi_close_handle_scope(env, scope);
354     return instance;
355 }
356 
DeclareDeviceCoordinationInterface(napi_env env,napi_value exports)357 void JsCooperateContext::DeclareDeviceCoordinationInterface(napi_env env, napi_value exports)
358 {
359     napi_value infoStart = nullptr;
360     CHKRV(napi_create_int32(env,
361         static_cast<int32_t>(JsEventCooperateTarget::CooperateMessage::INFO_START), &infoStart), CREATE_INT32);
362     napi_value infoSuccess = nullptr;
363     CHKRV(napi_create_int32(env,
364         static_cast<int32_t>(JsEventCooperateTarget::CooperateMessage::INFO_SUCCESS), &infoSuccess), CREATE_INT32);
365     napi_value infoFail = nullptr;
366     CHKRV(napi_create_int32(env, static_cast<int32_t>(JsEventCooperateTarget::CooperateMessage::INFO_FAIL), &infoFail),
367         CREATE_INT32);
368     napi_value stateOn = nullptr;
369     CHKRV(napi_create_int32(env, static_cast<int32_t>(JsEventCooperateTarget::CooperateMessage::STATE_ON), &stateOn),
370         CREATE_INT32);
371     napi_value stateOff = nullptr;
372     CHKRV(napi_create_int32(env, static_cast<int32_t>(JsEventCooperateTarget::CooperateMessage::STATE_OFF), &stateOff),
373         CREATE_INT32);
374 
375     napi_property_descriptor msg[] = {
376         DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_INFO_START", infoStart),
377         DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_INFO_SUCCESS", infoSuccess),
378         DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_INFO_FAIL", infoFail),
379         DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_STATE_ON", stateOn),
380         DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_STATE_OFF", stateOff)
381     };
382 
383     napi_value eventMsg = nullptr;
384     CHKRV(napi_define_class(env, "EventMsg", NAPI_AUTO_LENGTH, EnumClassConstructor, nullptr,
385         sizeof(msg) / sizeof(*msg), msg, &eventMsg), DEFINE_CLASS);
386     CHKRV(napi_set_named_property(env, exports, "EventMsg", eventMsg), SET_NAMED_PROPERTY);
387 }
388 
DeclareDeviceCoordinationData(napi_env env,napi_value exports)389 void JsCooperateContext::DeclareDeviceCoordinationData(napi_env env, napi_value exports)
390 {
391     napi_property_descriptor functions[] = {
392         DECLARE_NAPI_STATIC_FUNCTION("enable", Enable),
393         DECLARE_NAPI_STATIC_FUNCTION("start", Start),
394         DECLARE_NAPI_STATIC_FUNCTION("stop", Stop),
395         DECLARE_NAPI_STATIC_FUNCTION("getState", GetState),
396         DECLARE_NAPI_STATIC_FUNCTION("on", On),
397         DECLARE_NAPI_STATIC_FUNCTION("off", Off)
398     };
399     CHKRV(napi_define_properties(env, exports,
400         sizeof(functions) / sizeof(*functions), functions), DEFINE_PROPERTIES);
401 }
402 
EnumClassConstructor(napi_env env,napi_callback_info info)403 napi_value JsCooperateContext::EnumClassConstructor(napi_env env, napi_callback_info info)
404 {
405     size_t argc = ZERO_PARAM;
406     napi_value args[ONE_PARAM] = { nullptr };
407     napi_value result = nullptr;
408     void *data = nullptr;
409     CHKRP(napi_get_cb_info(env, info, &argc, args, &result, &data), GET_CB_INFO);
410     return result;
411 }
412 } // namespace DeviceStatus
413 } // namespace Msdp
414 } // namespace OHOS
415