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