1 /*
2 * Copyright (c) 2021-2024 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 "module_template.h"
17
18 #include <algorithm>
19 #include <functional>
20 #include <initializer_list>
21 #include <memory>
22 #include <new>
23 #include <string>
24
25 #include "event_manager.h"
26 #include "netstack_log.h"
27 #ifndef CROSS_PLATFORM
28 #include "hi_app_event_report.h"
29 #endif
30
31 namespace OHOS::NetStack::ModuleTemplate {
32 static constexpr const int EVENT_PARAM_NUM = 2;
33 static constexpr const char *INTERFACE_LOCAL_SOCKET = "LocalSocket";
34 static constexpr const char *INTERFACE_TLS_SOCKET = "TLSSocket";
35 static constexpr const char *INTERFACE_WEB_SOCKET = "WebSocket";
36 static constexpr const char *INTERFACE_HTTP_REQUEST = "OHOS_NET_HTTP_HttpRequest";
37 static constexpr const char *INTERFACE_WEB_SOCKET_SERVER = "WebSocketServer";
38 static constexpr const char *EVENT_MANAGER = "EVENT_MANAGER";
39
OnManagerWrapper(napi_env env,napi_callback_info info,const std::initializer_list<std::string> & events,bool asyncCallback)40 napi_value OnManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
41 bool asyncCallback)
42 {
43 napi_value thisVal = nullptr;
44 size_t paramsCount = MAX_PARAM_NUM;
45 napi_value params[MAX_PARAM_NUM] = {nullptr};
46 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
47
48 if (paramsCount != EVENT_PARAM_NUM || NapiUtils::GetValueType(env, params[0]) != napi_string ||
49 NapiUtils::GetValueType(env, params[1]) != napi_function) {
50 NETSTACK_LOGE("on off once interface para: [string, function]");
51 napi_throw_error(env, std::to_string(PARSE_ERROR_CODE).c_str(), PARSE_ERROR_MSG);
52 return NapiUtils::GetUndefined(env);
53 }
54
55 std::string event = NapiUtils::GetStringFromValueUtf8(env, params[0]);
56 if (std::find(events.begin(), events.end(), event) == events.end()) {
57 return NapiUtils::GetUndefined(env);
58 }
59
60 EventManagerWrapper *wrapper = nullptr;
61 auto napiRet = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&wrapper));
62 if (napiRet != napi_ok) {
63 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
64 return NapiUtils::GetUndefined(env);
65 }
66 if (wrapper == nullptr) {
67 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
68 return NapiUtils::GetUndefined(env);
69 }
70 auto manager = wrapper->sharedManager;
71 if (manager == nullptr) {
72 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
73 return NapiUtils::GetUndefined(env);
74 }
75 if (manager != nullptr) {
76 manager->AddListener(env, event, params[1], false, asyncCallback);
77 }
78
79 return NapiUtils::GetUndefined(env);
80 }
81
OnceManagerWrapper(napi_env env,napi_callback_info info,const std::initializer_list<std::string> & events,bool asyncCallback)82 napi_value OnceManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
83 bool asyncCallback)
84 {
85 napi_value thisVal = nullptr;
86 size_t paramsCount = MAX_PARAM_NUM;
87 napi_value params[MAX_PARAM_NUM] = {nullptr};
88 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
89
90 if (paramsCount != EVENT_PARAM_NUM || NapiUtils::GetValueType(env, params[0]) != napi_string ||
91 NapiUtils::GetValueType(env, params[1]) != napi_function) {
92 NETSTACK_LOGE("on off once interface para: [string, function]");
93 return NapiUtils::GetUndefined(env);
94 }
95
96 std::string event = NapiUtils::GetStringFromValueUtf8(env, params[0]);
97 if (std::find(events.begin(), events.end(), event) == events.end()) {
98 return NapiUtils::GetUndefined(env);
99 }
100
101 EventManagerWrapper *wrapper = nullptr;
102 auto napiRet = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&wrapper));
103 if (napiRet != napi_ok) {
104 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
105 return NapiUtils::GetUndefined(env);
106 }
107 if (wrapper == nullptr) {
108 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
109 return NapiUtils::GetUndefined(env);
110 }
111 auto manager = wrapper->sharedManager;
112 if (manager != nullptr) {
113 manager->AddListener(env, event, params[1], true, asyncCallback);
114 }
115
116 return NapiUtils::GetUndefined(env);
117 }
118
OffManagerWrapper(napi_env env,napi_callback_info info,const std::initializer_list<std::string> & events)119 napi_value OffManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events)
120 {
121 napi_value thisVal = nullptr;
122 size_t paramsCount = MAX_PARAM_NUM;
123 napi_value params[MAX_PARAM_NUM] = {nullptr};
124 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
125
126 if ((paramsCount != 1 && paramsCount != EVENT_PARAM_NUM) ||
127 NapiUtils::GetValueType(env, params[0]) != napi_string) {
128 NETSTACK_LOGE("on off once interface para: [string, function?]");
129 napi_throw_error(env, std::to_string(PARSE_ERROR_CODE).c_str(), PARSE_ERROR_MSG);
130 return NapiUtils::GetUndefined(env);
131 }
132
133 if (paramsCount == EVENT_PARAM_NUM && NapiUtils::GetValueType(env, params[1]) != napi_function) {
134 NETSTACK_LOGE("on off once interface para: [string, function]");
135 napi_throw_error(env, std::to_string(PARSE_ERROR_CODE).c_str(), PARSE_ERROR_MSG);
136 return NapiUtils::GetUndefined(env);
137 }
138
139 std::string event = NapiUtils::GetStringFromValueUtf8(env, params[0]);
140 if (std::find(events.begin(), events.end(), event) == events.end()) {
141 return NapiUtils::GetUndefined(env);
142 }
143
144 EventManagerWrapper *wrapper = nullptr;
145 auto napiRet = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&wrapper));
146 if (napiRet != napi_ok) {
147 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
148 return NapiUtils::GetUndefined(env);
149 }
150 if (wrapper == nullptr) {
151 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
152 return NapiUtils::GetUndefined(env);
153 }
154 auto manager = wrapper->sharedManager;
155 if (manager == nullptr) {
156 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
157 return NapiUtils::GetUndefined(env);
158 }
159 if (manager != nullptr) {
160 if (paramsCount == EVENT_PARAM_NUM) {
161 manager->DeleteListener(event, params[1]);
162 } else {
163 manager->DeleteListener(event);
164 }
165 }
166
167 return NapiUtils::GetUndefined(env);
168 }
169
OnSharedManager(napi_env env,napi_callback_info info,const std::initializer_list<std::string> & events,bool asyncCallback)170 napi_value OnSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
171 bool asyncCallback)
172 {
173 napi_value thisVal = nullptr;
174 size_t paramsCount = MAX_PARAM_NUM;
175 napi_value params[MAX_PARAM_NUM] = {nullptr};
176 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
177
178 if (paramsCount != EVENT_PARAM_NUM || NapiUtils::GetValueType(env, params[0]) != napi_string ||
179 NapiUtils::GetValueType(env, params[1]) != napi_function) {
180 NETSTACK_LOGE("on off once interface para: [string, function]");
181 napi_throw_error(env, std::to_string(PARSE_ERROR_CODE).c_str(), PARSE_ERROR_MSG);
182 return NapiUtils::GetUndefined(env);
183 }
184
185 std::string event = NapiUtils::GetStringFromValueUtf8(env, params[0]);
186 if (std::find(events.begin(), events.end(), event) == events.end()) {
187 return NapiUtils::GetUndefined(env);
188 }
189
190 std::shared_ptr<EventManager> *sharedManager = nullptr;
191 auto napiRet = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&sharedManager));
192 if (napiRet != napi_ok) {
193 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
194 return NapiUtils::GetUndefined(env);
195 }
196 if (sharedManager == nullptr) {
197 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
198 return NapiUtils::GetUndefined(env);
199 }
200 auto manager = *sharedManager;
201 if (manager == nullptr) {
202 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
203 return NapiUtils::GetUndefined(env);
204 }
205 if (manager != nullptr) {
206 manager->AddListener(env, event, params[1], false, asyncCallback);
207 }
208
209 return NapiUtils::GetUndefined(env);
210 }
211
OnceSharedManager(napi_env env,napi_callback_info info,const std::initializer_list<std::string> & events,bool asyncCallback)212 napi_value OnceSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
213 bool asyncCallback)
214 {
215 napi_value thisVal = nullptr;
216 size_t paramsCount = MAX_PARAM_NUM;
217 napi_value params[MAX_PARAM_NUM] = {nullptr};
218 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
219
220 if (paramsCount != EVENT_PARAM_NUM || NapiUtils::GetValueType(env, params[0]) != napi_string ||
221 NapiUtils::GetValueType(env, params[1]) != napi_function) {
222 NETSTACK_LOGE("on off once interface para: [string, function]");
223 return NapiUtils::GetUndefined(env);
224 }
225
226 std::string event = NapiUtils::GetStringFromValueUtf8(env, params[0]);
227 if (std::find(events.begin(), events.end(), event) == events.end()) {
228 return NapiUtils::GetUndefined(env);
229 }
230
231 std::shared_ptr<EventManager> *sharedManager = nullptr;
232 auto napiRet = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&sharedManager));
233 if (napiRet != napi_ok) {
234 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
235 return NapiUtils::GetUndefined(env);
236 }
237 if (sharedManager == nullptr) {
238 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
239 return NapiUtils::GetUndefined(env);
240 }
241 auto manager = *sharedManager;
242 if (manager != nullptr) {
243 manager->AddListener(env, event, params[1], true, asyncCallback);
244 }
245
246 return NapiUtils::GetUndefined(env);
247 }
248
OffSharedManager(napi_env env,napi_callback_info info,const std::initializer_list<std::string> & events)249 napi_value OffSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events)
250 {
251 napi_value thisVal = nullptr;
252 size_t paramsCount = MAX_PARAM_NUM;
253 napi_value params[MAX_PARAM_NUM] = {nullptr};
254 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
255
256 if ((paramsCount != 1 && paramsCount != EVENT_PARAM_NUM) ||
257 NapiUtils::GetValueType(env, params[0]) != napi_string) {
258 NETSTACK_LOGE("on off once interface para: [string, function?]");
259 napi_throw_error(env, std::to_string(PARSE_ERROR_CODE).c_str(), PARSE_ERROR_MSG);
260 return NapiUtils::GetUndefined(env);
261 }
262
263 if (paramsCount == EVENT_PARAM_NUM && NapiUtils::GetValueType(env, params[1]) != napi_function) {
264 NETSTACK_LOGE("on off once interface para: [string, function]");
265 napi_throw_error(env, std::to_string(PARSE_ERROR_CODE).c_str(), PARSE_ERROR_MSG);
266 return NapiUtils::GetUndefined(env);
267 }
268
269 std::string event = NapiUtils::GetStringFromValueUtf8(env, params[0]);
270 if (std::find(events.begin(), events.end(), event) == events.end()) {
271 return NapiUtils::GetUndefined(env);
272 }
273
274 std::shared_ptr<EventManager> *sharedManager = nullptr;
275 auto napiRet = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&sharedManager));
276 if (napiRet != napi_ok) {
277 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
278 return NapiUtils::GetUndefined(env);
279 }
280 if (sharedManager == nullptr) {
281 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
282 return NapiUtils::GetUndefined(env);
283 }
284 auto manager = *sharedManager;
285 if (manager == nullptr) {
286 NETSTACK_LOGE("get event manager in napi_unwrap failed, napiRet is %{public}d", napiRet);
287 return NapiUtils::GetUndefined(env);
288 }
289 if (manager != nullptr) {
290 if (paramsCount == EVENT_PARAM_NUM) {
291 manager->DeleteListener(event, params[1]);
292 } else {
293 manager->DeleteListener(event);
294 }
295 }
296
297 return NapiUtils::GetUndefined(env);
298 }
299
CleanUpWithSharedManager(void * data)300 void CleanUpWithSharedManager(void* data)
301 {
302 auto sharedManager = reinterpret_cast<std::shared_ptr<EventManager> *>(data);
303 if (sharedManager == nullptr || *sharedManager == nullptr) {
304 return;
305 }
306 auto manager = *sharedManager;
307 auto env = manager->env_;
308 napi_value obj = nullptr;
309 void* result = nullptr;
310 napi_get_named_property(env, NapiUtils::GetGlobal(env), manager->className_.c_str(), &obj);
311 napi_remove_wrap(env, obj, &result);
312 }
313
DefineClass(napi_env env,napi_value exports,const std::initializer_list<napi_property_descriptor> & properties,const std::string & className)314 void DefineClass(napi_env env, napi_value exports, const std::initializer_list<napi_property_descriptor> &properties,
315 const std::string &className)
316 {
317 auto constructor = [](napi_env env, napi_callback_info info) -> napi_value {
318 napi_value thisVal = nullptr;
319 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVal, nullptr));
320
321 return thisVal;
322 };
323
324 napi_value jsConstructor = nullptr;
325
326 napi_property_descriptor descriptors[properties.size()];
327 std::copy(properties.begin(), properties.end(), descriptors);
328
329 NAPI_CALL_RETURN_VOID(env, napi_define_class(env, className.c_str(), NAPI_AUTO_LENGTH, constructor, nullptr,
330 properties.size(), descriptors, &jsConstructor));
331 (void)exports;
332 auto global = NapiUtils::GetGlobal(env);
333 NapiUtils::SetNamedProperty(env, global, className, jsConstructor);
334 }
335
NewInstanceWithManagerWrapper(napi_env env,napi_callback_info info,const std::string & className,Finalizer finalizer)336 napi_value NewInstanceWithManagerWrapper(napi_env env, napi_callback_info info, const std::string &className,
337 Finalizer finalizer)
338 {
339 NETSTACK_LOGD("create new instance for %{public}s", className.c_str());
340 napi_value thisVal = nullptr;
341 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVal, nullptr));
342
343 auto global = NapiUtils::GetGlobal(env);
344 napi_value jsConstructor = NapiUtils::GetNamedProperty(env, global, className);
345 if (NapiUtils::GetValueType(env, jsConstructor) == napi_undefined) {
346 return nullptr;
347 }
348
349 napi_value result = nullptr;
350 NAPI_CALL(env, napi_new_instance(env, jsConstructor, 0, nullptr, &result));
351
352 auto wrapper = new EventManagerWrapper;
353 auto manager = std::make_shared<EventManager>();
354 wrapper->sharedManager = manager;
355 if (className == INTERFACE_HTTP_REQUEST || className == INTERFACE_LOCAL_SOCKET ||
356 className == INTERFACE_TLS_SOCKET || className == INTERFACE_WEB_SOCKET ||
357 className == INTERFACE_WEB_SOCKET_SERVER) {
358 NETSTACK_LOGD("create reference for %{public}s", className.c_str());
359 manager->CreateEventReference(env, thisVal);
360 }
361 napi_wrap(env, result, reinterpret_cast<void *>(wrapper), finalizer, nullptr, nullptr);
362
363 return result;
364 }
365
NewInstanceWithSharedManager(napi_env env,napi_callback_info info,const std::string & className,Finalizer finalizer)366 napi_value NewInstanceWithSharedManager(napi_env env, napi_callback_info info, const std::string &className,
367 Finalizer finalizer)
368 {
369 NETSTACK_LOGD("create new instance for %{public}s", className.c_str());
370 #ifndef CROSS_PLATFORM
371 HiAppEventReport hiAppEventReport("NetworkKit", "WebsocketConstructLocalSocketInstance");
372 #endif
373 napi_value thisVal = nullptr;
374 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVal, nullptr));
375
376 auto global = NapiUtils::GetGlobal(env);
377 napi_value jsConstructor = NapiUtils::GetNamedProperty(env, global, className);
378 if (NapiUtils::GetValueType(env, jsConstructor) == napi_undefined) {
379 return nullptr;
380 }
381
382 napi_value result = nullptr;
383 NAPI_CALL(env, napi_new_instance(env, jsConstructor, 0, nullptr, &result));
384
385 auto sharedManager = new (std::nothrow) std::shared_ptr<EventManager>();
386 if (sharedManager == nullptr) {
387 return result;
388 }
389 auto manager = std::make_shared<EventManager>();
390 manager->env_ = env;
391 manager->className_ = className + EVENT_MANAGER;
392 manager->finalizer_ = finalizer;
393 *sharedManager = manager;
394 if (className == INTERFACE_HTTP_REQUEST || className == INTERFACE_LOCAL_SOCKET ||
395 className == INTERFACE_TLS_SOCKET || className == INTERFACE_WEB_SOCKET ||
396 className == INTERFACE_WEB_SOCKET_SERVER) {
397 NETSTACK_LOGD("create reference for %{public}s", className.c_str());
398 manager->CreateEventReference(env, thisVal);
399 }
400 napi_wrap(env, result, reinterpret_cast<void *>(sharedManager),
401 [](napi_env env, void *data, void *hint) {
402 napi_remove_env_cleanup_hook(env, CleanUpWithSharedManager, data);
403 auto sharedManager = reinterpret_cast<std::shared_ptr<EventManager> *>(data);
404 if (sharedManager == nullptr || *sharedManager == nullptr || (*sharedManager)->finalizer_ == nullptr) {
405 return;
406 }
407 auto manager = *sharedManager;
408 manager->finalizer_(env, data, hint);
409 },
410 nullptr, nullptr);
411 napi_set_named_property(env, global, manager->className_.c_str(), result);
412 napi_add_env_cleanup_hook(env, CleanUpWithSharedManager, reinterpret_cast<void *>(sharedManager));
413 #ifndef CROSS_PLATFORM
414 hiAppEventReport.ReportSdkEvent(RESULT_SUCCESS, ERR_NONE);
415 #endif
416 return result;
417 }
418
NewInstanceNoManager(napi_env env,napi_callback_info info,const std::string & name,Finalizer finalizer)419 napi_value NewInstanceNoManager(napi_env env, napi_callback_info info, const std::string &name, Finalizer finalizer)
420 {
421 napi_value thisVal = nullptr;
422 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVal, nullptr));
423 (void)thisVal;
424 auto global = NapiUtils::GetGlobal(env);
425 napi_value jsConstructor = NapiUtils::GetNamedProperty(env, global, name);
426 if (NapiUtils::GetValueType(env, jsConstructor) == napi_undefined) {
427 return nullptr;
428 }
429
430 napi_value result = nullptr;
431 NAPI_CALL(env, napi_new_instance(env, jsConstructor, 0, nullptr, &result));
432
433 return result;
434 }
435 } // namespace OHOS::NetStack::ModuleTemplate
436