1 /*
2 * Copyright (c) 2021-2022 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 #ifndef COMMUNICATIONNETSTACK_NETSTACK_MODULE_TEMPLATE_H
17 #define COMMUNICATIONNETSTACK_NETSTACK_MODULE_TEMPLATE_H
18
19 #include <cstddef>
20 #include <initializer_list>
21 #include <iosfwd>
22 #include <type_traits>
23 #include <vector>
24
25 #include "base_async_work.h"
26 #include "base_context.h"
27 #include "napi/native_api.h"
28 #include "napi/native_common.h"
29 #include "napi_utils.h"
30 #include "netstack_log.h"
31
32 namespace OHOS::NetStack {
33 class EventManager;
34 struct EventManagerWrapper;
35 } // namespace OHOS::NetStack
36
37 #define MAX_PARAM_NUM 64
38
39 namespace OHOS::NetStack::ModuleTemplate {
40
41 template <class Context>
InterfaceWithManagerWrapper(napi_env env,napi_callback_info info,const std::string & asyncWorkName,bool (* Work)(napi_env,napi_value,Context *),AsyncWorkExecutor executor,AsyncWorkCallback callback)42 napi_value InterfaceWithManagerWrapper(napi_env env, napi_callback_info info, const std::string &asyncWorkName,
43 bool (*Work)(napi_env, napi_value, Context *), AsyncWorkExecutor executor,
44 AsyncWorkCallback callback)
45 {
46 NETSTACK_LOGI("js invoke %{public}s", asyncWorkName.c_str());
47 static_assert(std::is_base_of<BaseContext, Context>::value);
48
49 napi_value thisVal = nullptr;
50 size_t paramsCount = MAX_PARAM_NUM;
51 napi_value params[MAX_PARAM_NUM] = {nullptr};
52 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
53
54 EventManagerWrapper *wrapper = nullptr;
55 auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&wrapper));
56 if (napi_ret != napi_ok) {
57 NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
58 return NapiUtils::GetUndefined(env);
59 }
60
61 std::shared_ptr<EventManager> sharedManager = nullptr;
62 if (wrapper) {
63 sharedManager = wrapper->sharedManager;
64 }
65 auto context = new (std::nothrow) Context(env, sharedManager);
66 if (!context) {
67 NETSTACK_LOGE("new context is nullptr");
68 return NapiUtils::GetUndefined(env);
69 }
70 context->ParseParams(params, paramsCount);
71 if (context->IsNeedThrowException()) { // only api9 or later need throw exception.
72 napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
73 delete context;
74 context = nullptr;
75 return NapiUtils::GetUndefined(env);
76 }
77 if (Work != nullptr) {
78 if (!Work(env, thisVal, context)) {
79 NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
80 }
81 }
82
83 context->CreateReference(thisVal);
84 context->CreateAsyncWork(asyncWorkName, executor, callback);
85 if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
86 NETSTACK_LOGD("%{public}s create promise", asyncWorkName.c_str());
87 return context->CreatePromise();
88 }
89 return NapiUtils::GetUndefined(env);
90 }
91
92 template <class Context>
InterfaceWithSharedManager(napi_env env,napi_callback_info info,const std::string & asyncWorkName,bool (* Work)(napi_env,napi_value,Context *),AsyncWorkExecutor executor,AsyncWorkCallback callback)93 napi_value InterfaceWithSharedManager(napi_env env, napi_callback_info info, const std::string &asyncWorkName,
94 bool (*Work)(napi_env, napi_value, Context *), AsyncWorkExecutor executor,
95 AsyncWorkCallback callback)
96 {
97 NETSTACK_LOGI("js invoke %{public}s", asyncWorkName.c_str());
98 static_assert(std::is_base_of<BaseContext, Context>::value);
99
100 napi_value thisVal = nullptr;
101 size_t paramsCount = MAX_PARAM_NUM;
102 napi_value params[MAX_PARAM_NUM] = {nullptr};
103 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
104
105 std::shared_ptr<EventManager> *sharedManager = nullptr;
106 auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&sharedManager));
107 if (napi_ret != napi_ok) {
108 NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
109 return NapiUtils::GetUndefined(env);
110 }
111 std::shared_ptr<EventManager> manager = nullptr;
112 if (sharedManager != nullptr && *sharedManager != nullptr) {
113 manager = *sharedManager;
114 }
115
116 auto context = new (std::nothrow) Context(env, manager);
117 if (!context) {
118 NETSTACK_LOGE("new context is nullptr");
119 return NapiUtils::GetUndefined(env);
120 }
121 context->ParseParams(params, paramsCount);
122 if (context->IsNeedThrowException()) { // only api9 or later need throw exception.
123 napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
124 delete context;
125 context = nullptr;
126 return NapiUtils::GetUndefined(env);
127 }
128 if (Work != nullptr) {
129 if (!Work(env, thisVal, context)) {
130 NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
131 }
132 }
133
134 context->CreateReference(thisVal);
135 context->CreateAsyncWork(asyncWorkName, executor, callback);
136 if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
137 NETSTACK_LOGD("%{public}s create promise", asyncWorkName.c_str());
138 return context->CreatePromise();
139 }
140 return NapiUtils::GetUndefined(env);
141 }
142
143 template <class Context>
InterfaceWithOutAsyncWorkWithManagerWrapper(napi_env env,napi_callback_info info,bool (* Work)(napi_env,napi_value,Context *),const std::string & asyncWorkName,AsyncWorkExecutor executor,AsyncWorkCallback callback)144 napi_value InterfaceWithOutAsyncWorkWithManagerWrapper(napi_env env, napi_callback_info info,
145 bool (*Work)(napi_env, napi_value, Context *),
146 const std::string &asyncWorkName, AsyncWorkExecutor executor,
147 AsyncWorkCallback callback)
148 {
149 static_assert(std::is_base_of<BaseContext, Context>::value);
150
151 napi_value thisVal = nullptr;
152 size_t paramsCount = MAX_PARAM_NUM;
153 napi_value params[MAX_PARAM_NUM] = {nullptr};
154 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
155
156 EventManagerWrapper *wrapper = nullptr;
157 auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&wrapper));
158 if (napi_ret != napi_ok) {
159 NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
160 return NapiUtils::GetUndefined(env);
161 }
162
163 std::shared_ptr<EventManager> sharedManager = nullptr;
164 if (wrapper) {
165 sharedManager = wrapper->sharedManager;
166 }
167 auto context = new (std::nothrow) Context(env, sharedManager);
168 if (!context) {
169 NETSTACK_LOGE("new context is nullptr");
170 return NapiUtils::GetUndefined(env);
171 }
172 context->ParseParams(params, paramsCount);
173 napi_value ret = NapiUtils::GetUndefined(env);
174 if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
175 NETSTACK_LOGD("%{public}s is invoked in promise mode", asyncWorkName.c_str());
176 ret = context->CreatePromise();
177 } else {
178 NETSTACK_LOGD("%{public}s is invoked in callback mode", asyncWorkName.c_str());
179 }
180 context->CreateReference(thisVal);
181 if (Work != nullptr) {
182 if (!Work(env, thisVal, context)) {
183 NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
184 }
185 }
186 if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
187 context->IsCleartextNotPermitted() || context->GetSharedManager()->IsEventDestroy()) {
188 context->CreateAsyncWork(asyncWorkName, executor, callback);
189 }
190 return ret;
191 }
192
193 template <class Context>
InterfaceWithOutAsyncWorkWithSharedManager(napi_env env,napi_callback_info info,bool (* Work)(napi_env,napi_value,Context *),const std::string & asyncWorkName,AsyncWorkExecutor executor,AsyncWorkCallback callback)194 napi_value InterfaceWithOutAsyncWorkWithSharedManager(napi_env env, napi_callback_info info,
195 bool (*Work)(napi_env, napi_value, Context *),
196 const std::string &asyncWorkName, AsyncWorkExecutor executor,
197 AsyncWorkCallback callback)
198 {
199 static_assert(std::is_base_of<BaseContext, Context>::value);
200
201 napi_value thisVal = nullptr;
202 size_t paramsCount = MAX_PARAM_NUM;
203 napi_value params[MAX_PARAM_NUM] = {nullptr};
204 NAPI_CALL(env, napi_get_cb_info(env, info, ¶msCount, params, &thisVal, nullptr));
205
206 std::shared_ptr<EventManager> *sharedManager = nullptr;
207 auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&sharedManager));
208 if (napi_ret != napi_ok) {
209 NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
210 return NapiUtils::GetUndefined(env);
211 }
212 std::shared_ptr<EventManager> manager = nullptr;
213 if (sharedManager != nullptr && *sharedManager != nullptr) {
214 manager = *sharedManager;
215 }
216
217 auto context = new (std::nothrow) Context(env, manager);
218 if (!context) {
219 NETSTACK_LOGE("new context is nullptr");
220 return NapiUtils::GetUndefined(env);
221 }
222 context->ParseParams(params, paramsCount);
223 napi_value ret = NapiUtils::GetUndefined(env);
224 if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
225 NETSTACK_LOGD("%{public}s is invoked in promise mode", asyncWorkName.c_str());
226 ret = context->CreatePromise();
227 } else {
228 NETSTACK_LOGD("%{public}s is invoked in callback mode", asyncWorkName.c_str());
229 }
230 context->CreateReference(thisVal);
231 if (Work != nullptr) {
232 if (!Work(env, thisVal, context)) {
233 NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
234 }
235 }
236 if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
237 context->IsCleartextNotPermitted() || context->GetSharedManager()->IsEventDestroy()) {
238 context->CreateAsyncWork(asyncWorkName, executor, callback);
239 }
240 return ret;
241 }
242
CallbackTemplate(uv_work_t * work,int status)243 template <napi_value (*MakeJsValue)(napi_env, void *)> static void CallbackTemplate(uv_work_t *work, int status)
244 {
245 (void)status;
246
247 auto workWrapper = static_cast<UvWorkWrapperShared *>(work->data);
248 napi_env env = workWrapper->env;
249 auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
250 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
251
252 napi_value obj = MakeJsValue(env, workWrapper->data);
253
254 std::pair<napi_value, napi_value> arg = {NapiUtils::GetUndefined(workWrapper->env), obj};
255 workWrapper->manager->Emit(workWrapper->type, arg);
256
257 delete workWrapper;
258 delete work;
259 }
260
261 template <napi_value (*MakeJsValue)(napi_env, const std::shared_ptr<EventManager> &)>
CallbackTemplateWithSharedManager(uv_work_t * work,int status)262 static void CallbackTemplateWithSharedManager(uv_work_t *work, int status)
263 {
264 (void)status;
265
266 auto workWrapper = static_cast<UvWorkWrapperShared *>(work->data);
267 napi_env env = workWrapper->env;
268 auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
269 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
270
271 napi_value obj = MakeJsValue(env, workWrapper->manager);
272
273 std::pair<napi_value, napi_value> arg = {NapiUtils::GetUndefined(workWrapper->env), obj};
274 workWrapper->manager->Emit(workWrapper->type, arg);
275
276 delete workWrapper;
277 delete work;
278 }
279
280 void CleanUpWithSharedManager(void* data);
281
282 void DefineClass(napi_env env, napi_value exports, const std::initializer_list<napi_property_descriptor> &properties,
283 const std::string &className);
284
285 napi_value NewInstanceNoManager(napi_env env, napi_callback_info info, const std::string &name, Finalizer finalizer);
286
287 napi_value NewInstanceWithSharedManager(napi_env env, napi_callback_info info, const std::string &className,
288 Finalizer finalizer);
289
290 napi_value NewInstanceWithManagerWrapper(napi_env env, napi_callback_info info, const std::string &className,
291 Finalizer finalizer);
292
293 napi_value OnSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
294 bool asyncCallback);
295
296 napi_value OnceSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
297 bool asyncCallback);
298
299 napi_value OffSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events);
300
301 napi_value OnManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
302 bool asyncCallback);
303
304 napi_value OnceManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
305 bool asyncCallback);
306
307 napi_value OffManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events);
308 } // namespace OHOS::NetStack::ModuleTemplate
309 #endif /* COMMUNICATIONNETSTACK_NETSTACK_MODULE_TEMPLATE_H */
310