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