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 
16 #ifndef LDBPROJ_NAPI_QUEUE_H
17 #define LDBPROJ_NAPI_QUEUE_H
18 
19 #include <functional>
20 #include <memory>
21 #include <string>
22 
23 #include "logger.h"
24 #include "napi/native_api.h"
25 #include "napi/native_common.h"
26 #include "napi/native_node_api.h"
27 
28 namespace OHOS::CloudData {
29 using namespace OHOS::Rdb;
30 
31 constexpr size_t ARGC_MAX = 6;
32 using NapiCbInfoParser = std::function<void(size_t argc, napi_value *argv)>;
33 using NapiAsyncExecute = std::function<void(void)>;
34 using NapiAsyncComplete = std::function<void(napi_value &)>;
35 
36 struct ContextBase {
37     virtual ~ContextBase();
38     void GetCbInfo(
39         napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser(), bool sync = false);
40 
41     inline void GetCbInfoSync(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser())
42     {
43         /* sync = true, means no callback, not AsyncWork. */
44         GetCbInfo(env, info, parse, true);
45     }
46 
47     napi_env env = nullptr;
48     napi_value output = nullptr;
49     napi_status status = napi_invalid_arg;
50     std::string error;
51     int32_t jsCode = 0;
52     bool isThrowError = false;
53 
54     napi_value self = nullptr;
55     void *native = nullptr;
56 
57 private:
58     napi_ref callbackRef = nullptr;
59     napi_ref selfRef = nullptr;
60     friend class NapiQueue;
61 };
62 
63 /* check condition related to argc/argv, return and logging. */
64 #define ASSERT_VALUE(ctxt, condition, errCode, message)          \
65     do {                                                         \
66         if (!(condition)) {                                      \
67             (ctxt)->status = errCode;                            \
68             (ctxt)->error = std::string(message);                \
69             LOG_ERROR("test (" #condition ") failed: " message); \
70             return;                                              \
71         }                                                        \
72     } while (0)
73 
74 #define ASSERT_ARGS(ctxt, condition, message)                    \
75     ASSERT_VALUE(ctxt, condition, napi_invalid_arg, message)
76 
77 #define ASSERT_STATUS(ctxt, message)                                      \
78     do {                                                                  \
79         if ((ctxt)->status != napi_ok) {                                  \
80             (ctxt)->error = std::string(message);                         \
81             LOG_ERROR("test (ctxt->status == napi_ok) failed: " message); \
82             return;                                                       \
83         }                                                                 \
84     } while (0)
85 
86 /* check condition, return and logging if condition not true. */
87 #define ASSERT(condition, message, retVal)                       \
88     do {                                                         \
89         if (!(condition)) {                                      \
90             LOG_ERROR("test (" #condition ") failed: " message); \
91             return retVal;                                       \
92         }                                                        \
93     } while (0)
94 
95 #define ASSERT_VOID(condition, message)                          \
96     do {                                                         \
97         if (!(condition)) {                                      \
98             LOG_ERROR("test (" #condition ") failed: " message); \
99             return;                                              \
100         }                                                        \
101     } while (0)
102 
103 #define ASSERT_NULL(condition, message) ASSERT(condition, message, nullptr)
104 
105 #define ASSERT_CALL(env, theCall, object)    \
106     do {                                     \
107         if ((theCall) != napi_ok) {          \
108             delete (object);                 \
109             GET_AND_THROW_LAST_ERROR((env)); \
110             return nullptr;                  \
111         }                                    \
112     } while (0)
113 
114 class NapiQueue {
115 public:
116     static napi_value AsyncWork(napi_env env, std::shared_ptr<ContextBase> ctxt, const std::string &name,
117         NapiAsyncExecute execute = NapiAsyncExecute(), NapiAsyncComplete complete = NapiAsyncComplete());
118 
119 private:
120     enum {
121         /* AsyncCallback / Promise output result index  */
122         RESULT_ERROR = 0,
123         RESULT_DATA = 1,
124         RESULT_ALL = 2
125     };
126 
127     struct AsyncContext {
128         napi_env env = nullptr;
129         std::shared_ptr<ContextBase> ctx;
130         NapiAsyncExecute execute = nullptr;
131         NapiAsyncComplete complete = nullptr;
132         napi_deferred deferred = nullptr;
133         napi_async_work work = nullptr;
~AsyncContextAsyncContext134         ~AsyncContext()
135         {
136             execute = nullptr;
137             complete = nullptr;
138             ctx = nullptr;
139             if (env != nullptr) {
140                 if (work != nullptr) {
141                     napi_delete_async_work(env, work);
142                 }
143             }
144         }
145     };
146     static void GenerateOutput(AsyncContext &ctx, napi_value output);
147 };
148 } // namespace OHOS::CloudData
149 #endif //LDBPROJ_NAPI_QUEUE_H
150