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, &paramsCount, 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     auto context = new (std::nothrow) Context(env, nullptr);
63     if (!context) {
64         NETSTACK_LOGE("new context is nullptr");
65         return NapiUtils::GetUndefined(env);
66     }
67     if (wrapper) {
68         context->SetSharedManager(wrapper->sharedManager);
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, &paramsCount, 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 
112     auto context = new (std::nothrow) Context(env, nullptr);
113     if (!context) {
114         NETSTACK_LOGE("new context is nullptr");
115         return NapiUtils::GetUndefined(env);
116     }
117     if (sharedManager) {
118         context->SetSharedManager(*sharedManager);
119     }
120     context->ParseParams(params, paramsCount);
121     if (context->IsNeedThrowException()) { // only api9 or later need throw exception.
122         napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
123         delete context;
124         context = nullptr;
125         return NapiUtils::GetUndefined(env);
126     }
127     if (Work != nullptr) {
128         if (!Work(env, thisVal, context)) {
129             NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
130         }
131     }
132 
133     context->CreateReference(thisVal);
134     context->CreateAsyncWork(asyncWorkName, executor, callback);
135     if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
136         NETSTACK_LOGD("%{public}s create promise", asyncWorkName.c_str());
137         return context->CreatePromise();
138     }
139     return NapiUtils::GetUndefined(env);
140 }
141 
142 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)143 napi_value InterfaceWithOutAsyncWorkWithManagerWrapper(napi_env env, napi_callback_info info,
144                                                        bool (*Work)(napi_env, napi_value, Context *),
145                                                        const std::string &asyncWorkName, AsyncWorkExecutor executor,
146                                                        AsyncWorkCallback callback)
147 {
148     static_assert(std::is_base_of<BaseContext, Context>::value);
149 
150     napi_value thisVal = nullptr;
151     size_t paramsCount = MAX_PARAM_NUM;
152     napi_value params[MAX_PARAM_NUM] = {nullptr};
153     NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
154 
155     EventManagerWrapper *wrapper = nullptr;
156     auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&wrapper));
157     if (napi_ret != napi_ok) {
158         NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
159         return NapiUtils::GetUndefined(env);
160     }
161 
162     auto context = new (std::nothrow) Context(env, nullptr);
163     if (!context) {
164         NETSTACK_LOGE("new context is nullptr");
165         return NapiUtils::GetUndefined(env);
166     }
167     if (wrapper) {
168         context->SetSharedManager(wrapper->sharedManager);
169     }
170     context->ParseParams(params, paramsCount);
171     napi_value ret = NapiUtils::GetUndefined(env);
172     if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
173         NETSTACK_LOGD("%{public}s is invoked in promise mode", asyncWorkName.c_str());
174         ret = context->CreatePromise();
175     } else {
176         NETSTACK_LOGD("%{public}s is invoked in callback mode", asyncWorkName.c_str());
177     }
178     context->CreateReference(thisVal);
179     if (Work != nullptr) {
180         if (!Work(env, thisVal, context)) {
181             NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
182         }
183     }
184     if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
185         context->GetSharedManager()->IsEventDestroy()) {
186         context->CreateAsyncWork(asyncWorkName, executor, callback);
187     }
188     return ret;
189 }
190 
191 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)192 napi_value InterfaceWithOutAsyncWorkWithSharedManager(napi_env env, napi_callback_info info,
193                                                       bool (*Work)(napi_env, napi_value, Context *),
194                                                       const std::string &asyncWorkName, AsyncWorkExecutor executor,
195                                                       AsyncWorkCallback callback)
196 {
197     static_assert(std::is_base_of<BaseContext, Context>::value);
198 
199     napi_value thisVal = nullptr;
200     size_t paramsCount = MAX_PARAM_NUM;
201     napi_value params[MAX_PARAM_NUM] = {nullptr};
202     NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
203 
204     std::shared_ptr<EventManager> *sharedManager = nullptr;
205     auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&sharedManager));
206     if (napi_ret != napi_ok) {
207         NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
208         return NapiUtils::GetUndefined(env);
209     }
210 
211     auto context = new (std::nothrow) Context(env, nullptr);
212     if (!context) {
213         NETSTACK_LOGE("new context is nullptr");
214         return NapiUtils::GetUndefined(env);
215     }
216     if (sharedManager) {
217         context->SetSharedManager(*sharedManager);
218     }
219     context->ParseParams(params, paramsCount);
220     napi_value ret = NapiUtils::GetUndefined(env);
221     if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
222         NETSTACK_LOGD("%{public}s is invoked in promise mode", asyncWorkName.c_str());
223         ret = context->CreatePromise();
224     } else {
225         NETSTACK_LOGD("%{public}s is invoked in callback mode", asyncWorkName.c_str());
226     }
227     context->CreateReference(thisVal);
228     if (Work != nullptr) {
229         if (!Work(env, thisVal, context)) {
230             NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
231         }
232     }
233     if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
234         context->GetSharedManager()->IsEventDestroy()) {
235         context->CreateAsyncWork(asyncWorkName, executor, callback);
236     }
237     return ret;
238 }
239 
240 template <class Context>
Interface(napi_env env,napi_callback_info info,const std::string & asyncWorkName,bool (* Work)(napi_env,napi_value,Context *),AsyncWorkExecutor executor,AsyncWorkCallback callback)241 napi_value Interface(napi_env env, napi_callback_info info, const std::string &asyncWorkName,
242                      bool (*Work)(napi_env, napi_value, Context *), AsyncWorkExecutor executor,
243                      AsyncWorkCallback callback)
244 {
245     NETSTACK_LOGI("js invoke %{public}s", asyncWorkName.c_str());
246     static_assert(std::is_base_of<BaseContext, Context>::value);
247 
248     napi_value thisVal = nullptr;
249     size_t paramsCount = MAX_PARAM_NUM;
250     napi_value params[MAX_PARAM_NUM] = {nullptr};
251     NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
252 
253     EventManager *manager = nullptr;
254     auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&manager));
255     if (napi_ret != napi_ok) {
256         NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
257         return NapiUtils::GetUndefined(env);
258     }
259 
260     auto context = new (std::nothrow) Context(env, manager);
261     if (!context) {
262         NETSTACK_LOGE("new context is nullptr");
263         return NapiUtils::GetUndefined(env);
264     }
265     context->ParseParams(params, paramsCount);
266     if (context->IsNeedThrowException()) { // only api9 or later need throw exception.
267         napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
268         delete context;
269         context = nullptr;
270         return NapiUtils::GetUndefined(env);
271     }
272     if (Work != nullptr) {
273         if (!Work(env, thisVal, context)) {
274             NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
275         }
276     }
277 
278     context->CreateReference(thisVal);
279     context->CreateAsyncWork(asyncWorkName, executor, callback);
280     if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
281         NETSTACK_LOGD("%{public}s create promise", asyncWorkName.c_str());
282         return context->CreatePromise();
283     }
284     return NapiUtils::GetUndefined(env);
285 }
286 
287 template <class Context>
InterfaceWithOutAsyncWork(napi_env env,napi_callback_info info,bool (* Work)(napi_env,napi_value,Context *),const std::string & asyncWorkName,AsyncWorkExecutor executor,AsyncWorkCallback callback)288 napi_value InterfaceWithOutAsyncWork(napi_env env, napi_callback_info info,
289                                      bool (*Work)(napi_env, napi_value, Context *), const std::string &asyncWorkName,
290                                      AsyncWorkExecutor executor, AsyncWorkCallback callback)
291 {
292     static_assert(std::is_base_of<BaseContext, Context>::value);
293 
294     napi_value thisVal = nullptr;
295     size_t paramsCount = MAX_PARAM_NUM;
296     napi_value params[MAX_PARAM_NUM] = {nullptr};
297     NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
298 
299     EventManager *manager = nullptr;
300     auto napi_ret = napi_unwrap(env, thisVal, reinterpret_cast<void **>(&manager));
301     if (napi_ret != napi_ok) {
302         NETSTACK_LOGE("get event manager in napi_unwrap failed, napi_ret is %{public}d", napi_ret);
303         return NapiUtils::GetUndefined(env);
304     }
305 
306     auto context = new (std::nothrow) Context(env, manager);
307     if (!context) {
308         NETSTACK_LOGE("new context is nullptr");
309         return NapiUtils::GetUndefined(env);
310     }
311     context->ParseParams(params, paramsCount);
312     napi_value ret = NapiUtils::GetUndefined(env);
313     if (NapiUtils::GetValueType(env, context->GetCallback()) != napi_function && context->IsNeedPromise()) {
314         NETSTACK_LOGD("%{public}s is invoked in promise mode", asyncWorkName.c_str());
315         ret = context->CreatePromise();
316     } else {
317         NETSTACK_LOGD("%{public}s is invoked in callback mode", asyncWorkName.c_str());
318     }
319     context->CreateReference(thisVal);
320     if (Work != nullptr) {
321         if (!Work(env, thisVal, context)) {
322             NETSTACK_LOGE("work failed error code = %{public}d", context->GetErrorCode());
323         }
324     }
325     if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
326         context->GetManager()->IsEventDestroy()) {
327         context->CreateAsyncWork(asyncWorkName, executor, callback);
328     }
329     return ret;
330 }
331 
332 napi_value On(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
333               bool asyncCallback);
334 
335 napi_value Once(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
336                 bool asyncCallback);
337 
338 napi_value Off(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events);
339 
340 void DefineClass(napi_env env, napi_value exports, const std::initializer_list<napi_property_descriptor> &properties,
341                  const std::string &className);
342 
343 napi_value NewInstance(napi_env env, napi_callback_info info, const std::string &className, Finalizer finalizer);
344 
345 napi_value NewInstanceNoManager(napi_env env, napi_callback_info info, const std::string &name, Finalizer finalizer);
346 
347 napi_value NewInstanceWithSharedManager(napi_env env, napi_callback_info info, const std::string &className,
348                                         Finalizer finalizer);
349 
350 napi_value NewInstanceWithManagerWrapper(napi_env env, napi_callback_info info, const std::string &className,
351                                          Finalizer finalizer);
352 
353 napi_value OnSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
354                            bool asyncCallback);
355 
356 napi_value OnceSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
357                              bool asyncCallback);
358 
359 napi_value OffSharedManager(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events);
360 
361 napi_value OnManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
362                             bool asyncCallback);
363 
364 napi_value OnceManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events,
365                               bool asyncCallback);
366 
367 napi_value OffManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list<std::string> &events);
368 } // namespace OHOS::NetStack::ModuleTemplate
369 #endif /* COMMUNICATIONNETSTACK_NETSTACK_MODULE_TEMPLATE_H */
370