• 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 #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