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 #ifndef ASYNC_CALL_H
16 #define ASYNC_CALL_H
17 
18 #include <functional>
19 #include <memory>
20 #include <string>
21 
22 #include "constant.h"
23 #include "js_common.h"
24 #include "log.h"
25 #include "napi/native_api.h"
26 #include "napi/native_node_api.h"
27 #include "napi_utils.h"
28 
29 namespace OHOS::Request {
30 class AsyncCall final {
31 public:
32     class Context {
33     public:
34         using InputAction = std::function<napi_status(size_t, napi_value *, napi_value)>;
35         using OutputAction = std::function<napi_status(napi_value *)>;
36         using ExecAction = std::function<void()>;
37         Context() = default;
~Context()38         virtual ~Context()
39         {
40             ContextNapiHolder *holder =
41                 new ContextNapiHolder{ .env = env_, .callbackRef = callbackRef_, .self = self_, .work = work_ };
42             auto afterCallback = [holder]() {
43                 napi_handle_scope scope = nullptr;
44                 napi_open_handle_scope(holder->env, &scope);
45                 if (scope == nullptr) {
46                     delete holder;
47                     return;
48                 } else if (holder->env == nullptr || holder->work == nullptr || holder->self == nullptr) {
49                     napi_close_handle_scope(holder->env, scope);
50                     delete holder;
51                     return;
52                 }
53                 napi_delete_async_work(holder->env, holder->work);
54                 napi_delete_reference(holder->env, holder->self);
55                 if (holder->callbackRef != nullptr) {
56                     napi_delete_reference(holder->env, holder->callbackRef);
57                 }
58                 napi_close_handle_scope(holder->env, scope);
59                 delete holder;
60             };
61             int32_t ret = napi_send_event(env_, afterCallback, napi_eprio_high);
62             if (ret != napi_ok) {
63                 REQUEST_HILOGE("napi_send_event failed: %{public}d", ret);
64                 delete holder;
65             }
66         };
SetInput(InputAction action)67         inline Context &SetInput(InputAction action)
68         {
69             input_ = std::move(action);
70             return *this;
71         }
SetOutput(OutputAction action)72         inline Context &SetOutput(OutputAction action)
73         {
74             output_ = std::move(action);
75             return *this;
76         }
SetExec(ExecAction action)77         inline Context &SetExec(ExecAction action)
78         {
79             exec_ = std::move(action);
80             return *this;
81         }
CreateErr()82         inline napi_value CreateErr()
83         {
84             ExceptionError error;
85             NapiUtils::ConvertError(innerCode_, error);
86             return NapiUtils::CreateBusinessError(env_, error.code, error.errInfo, withErrCode_);
87         }
88 
89         InputAction input_ = nullptr;
90         OutputAction output_ = nullptr;
91         ExecAction exec_ = nullptr;
92 
93         napi_env env_;
94         napi_ref callbackRef_ = nullptr;
95         napi_ref self_ = nullptr;
96         napi_deferred defer_ = nullptr;
97         napi_async_work work_ = nullptr;
98 
99         int32_t innerCode_;
100         bool withErrCode_;
101         Version version_;
102     };
103 
104     AsyncCall(napi_env env, napi_callback_info info, const std::shared_ptr<Context> &context);
105     ~AsyncCall();
106     napi_value Call(const std::shared_ptr<Context> &context, const std::string &resourceName = "AsyncCall");
107 
SetQosLevel(napi_qos_t napiQosLevel)108     inline void SetQosLevel(napi_qos_t napiQosLevel)
109     {
110         napiQosLevel_ = napiQosLevel;
111     }
112 
113 private:
114     enum { ARG_ERROR, ARG_DATA, ARG_BUTT };
115 
116     struct WorkData {
117         std::shared_ptr<Context> ctx = nullptr;
~WorkDataWorkData118         ~WorkData()
119         {
120             ctx = nullptr;
121         }
122     };
123 
124     struct ContextNapiHolder {
125         napi_env env;
126         napi_ref callbackRef;
127         napi_ref self;
128         napi_async_work work;
129     };
130     static void OnExecute(napi_env env, void *data);
131     static void OnComplete(napi_env env, napi_status status, void *data);
132     napi_qos_t napiQosLevel_ = napi_qos_default;
133 };
134 } // namespace OHOS::Request
135 #endif // ASYNC_CALL_H
136