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