1 /*
2 * Copyright (c) 2024 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 #define LOG_TAG "GdbStoreProxy"
16 #include "napi_gdb_store.h"
17
18 #include <algorithm>
19 #include <cinttypes>
20 #include <cstdint>
21 #include <vector>
22
23 #include "db_trace.h"
24 #include "js_utils.h"
25 #include "logger.h"
26 #include "napi_gdb_context.h"
27 #include "napi_gdb_error.h"
28 #include "napi_gdb_js_utils.h"
29 #include "napi_gdb_transaction.h"
30
31 namespace OHOS::GraphStoreJsKit {
32
GdbStoreProxy()33 GdbStoreProxy::GdbStoreProxy()
34 {
35 }
36
~GdbStoreProxy()37 GdbStoreProxy::~GdbStoreProxy()
38 {
39 }
40
GdbStoreProxy(std::shared_ptr<DBStore> gdbStore)41 GdbStoreProxy::GdbStoreProxy(std::shared_ptr<DBStore> gdbStore)
42 {
43 if (GetInstance() == gdbStore) {
44 return;
45 }
46 SetInstance(std::move(gdbStore));
47 }
48
operator =(std::shared_ptr<DBStore> gdbStore)49 GdbStoreProxy &GdbStoreProxy::operator=(std::shared_ptr<DBStore> gdbStore)
50 {
51 if (GetInstance() == gdbStore) {
52 return *this;
53 }
54 SetInstance(std::move(gdbStore));
55 return *this;
56 }
57
IsSystemAppCalled()58 bool GdbStoreProxy::IsSystemAppCalled()
59 {
60 return isSystemAppCalled_;
61 }
62
GetDescriptors()63 Descriptor GdbStoreProxy::GetDescriptors()
64 {
65 return []() -> std::vector<napi_property_descriptor> {
66 std::vector<napi_property_descriptor> properties = {
67 DECLARE_NAPI_FUNCTION("read", Read),
68 DECLARE_NAPI_FUNCTION("write", Write),
69 DECLARE_NAPI_FUNCTION("createTransaction", CreateTransaction),
70 DECLARE_NAPI_FUNCTION("close", Close),
71 };
72 return properties;
73 };
74 }
75
Init(napi_env env,napi_value exports)76 void GdbStoreProxy::Init(napi_env env, napi_value exports)
77 {
78 auto jsCtor = OHOS::AppDataMgrJsKit::JSUtils::DefineClass(
79 env, "ohos.data.graphStore", "GraphStore", GetDescriptors(), Initialize);
80 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, "GraphStore", jsCtor));
81 }
82
Destructor(napi_env env,void * nativeObject,void * finalize_hint)83 void GdbStoreProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
84 {
85 auto *obj = static_cast<GdbStoreProxy *>(nativeObject);
86 delete obj;
87 }
88
New(napi_env env,napi_callback_info info)89 napi_value GdbStoreProxy::New(napi_env env, napi_callback_info info)
90 {
91 size_t argc = 1;
92 napi_value argv[1] = { 0 };
93 napi_value thisVar = nullptr;
94 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
95
96 // get native object
97 auto *obj = new GdbStoreProxy();
98 ASSERT_CALL(env,
99 napi_wrap(env, thisVar, obj, GdbStoreProxy::Destructor,
100 nullptr, // finalize_hint
101 nullptr),
102 obj);
103 return thisVar;
104 }
105
Initialize(napi_env env,napi_callback_info info)106 napi_value GdbStoreProxy::Initialize(napi_env env, napi_callback_info info)
107 {
108 napi_value self = nullptr;
109 NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &self, nullptr));
110 auto finalize = [](napi_env env, void *data, void *hint) {
111 if (data != hint) {
112 LOG_ERROR("GdbStoreProxy memory corrupted! data:0x%016" PRIXPTR "hint:0x%016" PRIXPTR, uintptr_t(data),
113 uintptr_t(hint));
114 return;
115 }
116 GdbStoreProxy *proxy = reinterpret_cast<GdbStoreProxy *>(data);
117 proxy->SetInstance(nullptr);
118 delete proxy;
119 };
120 auto *proxy = new (std::nothrow) GdbStoreProxy();
121 if (proxy == nullptr) {
122 return nullptr;
123 }
124 napi_status status = napi_wrap(env, self, proxy, finalize, proxy, nullptr);
125 if (status != napi_ok) {
126 LOG_ERROR("GdbStoreProxy napi_wrap failed! code:%{public}d!", status);
127 finalize(env, proxy, proxy);
128 return nullptr;
129 }
130 return self;
131 }
132
NewInstance(napi_env env,std::shared_ptr<DBStore> value,bool isSystemAppCalled)133 napi_value GdbStoreProxy::NewInstance(napi_env env, std::shared_ptr<DBStore> value, bool isSystemAppCalled)
134 {
135 if (value == nullptr) {
136 LOG_ERROR("dbstore is nullptr");
137 return nullptr;
138 }
139 napi_value cons = OHOS::AppDataMgrJsKit::JSUtils::GetClass(env, "ohos.data.graphStore", "GraphStore");
140 if (cons == nullptr) {
141 LOG_ERROR("Constructor of ResultSet is nullptr!");
142 return nullptr;
143 }
144
145 napi_value instance = nullptr;
146 auto status = napi_new_instance(env, cons, 0, nullptr, &instance);
147 if (status != napi_ok) {
148 LOG_ERROR("GdbStoreProxy::NewInstance napi_new_instance failed! code:%{public}d!", status);
149 return nullptr;
150 }
151
152 GdbStoreProxy *proxy = nullptr;
153 status = napi_unwrap(env, instance, reinterpret_cast<void **>(&proxy));
154 if (proxy == nullptr) {
155 LOG_ERROR("GdbStoreProxy::NewInstance native instance is nullptr! code:%{public}d!", status);
156 return instance;
157 }
158 proxy->queue_ = std::make_shared<AppDataMgrJsKit::UvQueue>(env);
159 proxy->SetInstance(std::move(value));
160 proxy->isSystemAppCalled_ = isSystemAppCalled;
161 return instance;
162 }
163
GetNativeInstance(napi_env env,napi_value self)164 GdbStoreProxy *GetNativeInstance(napi_env env, napi_value self)
165 {
166 GdbStoreProxy *proxy = nullptr;
167 napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&proxy));
168 if (proxy == nullptr) {
169 LOG_ERROR("GdbStoreProxy native instance is nullptr! code:%{public}d!", status);
170 return nullptr;
171 }
172 return proxy;
173 }
174
ParseThis(const napi_env & env,const napi_value & self,const std::shared_ptr<GdbStoreContextBase> & context)175 int ParseThis(const napi_env &env, const napi_value &self, const std::shared_ptr<GdbStoreContextBase> &context)
176 {
177 GdbStoreProxy *obj = GetNativeInstance(env, self);
178 CHECK_RETURN_SET(obj != nullptr, std::make_shared<ParamError>("GdbStore", "not nullptr."));
179 CHECK_RETURN_SET(obj->GetInstance() != nullptr, std::make_shared<InnerError>(E_GRD_DB_INSTANCE_ABNORMAL));
180 context->boundObj = obj;
181 context->gdbStore = obj->GetInstance();
182 return OK;
183 }
184
ParseGql(const napi_env env,const napi_value arg,const std::shared_ptr<GdbStoreContext> & context)185 int ParseGql(const napi_env env, const napi_value arg, const std::shared_ptr<GdbStoreContext> &context)
186 {
187 context->gql = OHOS::AppDataMgrJsKit::JSUtils::Convert2String(env, arg);
188 CHECK_RETURN_SET(!context->gql.empty(), std::make_shared<ParamError>("gql", "not empty"));
189 CHECK_RETURN_SET(context->gql.size() <= GdbStoreProxy::MAX_GQL_LEN,
190 std::make_shared<ParamError>("gql", "too long"));
191 return OK;
192 }
193
Read(napi_env env,napi_callback_info info)194 napi_value GdbStoreProxy::Read(napi_env env, napi_callback_info info)
195 {
196 DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
197 auto context = std::make_shared<GdbStoreContext>();
198 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
199 CHECK_RETURN_SET_E(argc == 1, std::make_shared<ParamNumError>(" 1 "));
200 CHECK_RETURN(OK == ParseThis(env, self, context));
201 CHECK_RETURN(OK == ParseGql(env, argv[0], context));
202 };
203 auto exec = [context]() -> int {
204 CHECK_RETURN_ERR(context->gdbStore != nullptr);
205 auto queryResult = context->StealGdbStore()->QueryGql(context->gql);
206 context->result = queryResult.second;
207 context->intOutput = queryResult.first;
208 return OK;
209 };
210 auto output = [context](napi_env env, napi_value &result) {
211 result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result);
212 CHECK_RETURN_SET_E(context->intOutput == OK, std::make_shared<InnerError>(context->intOutput));
213 };
214 context->SetAction(env, info, input, exec, output);
215 CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
216 return ASYNC_CALL(env, context);
217 }
218
Write(napi_env env,napi_callback_info info)219 napi_value GdbStoreProxy::Write(napi_env env, napi_callback_info info)
220 {
221 DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
222 auto context = std::make_shared<GdbStoreContext>();
223 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
224 CHECK_RETURN_SET_E(argc == 1, std::make_shared<ParamNumError>(" 1 "));
225 CHECK_RETURN(OK == ParseThis(env, self, context));
226 CHECK_RETURN(OK == ParseGql(env, argv[0], context));
227 };
228 auto exec = [context]() -> int {
229 CHECK_RETURN_ERR(context->gdbStore != nullptr);
230 auto executeResult = context->StealGdbStore()->ExecuteGql(context->gql);
231 context->result = executeResult.second;
232 context->intOutput = executeResult.first;
233 return OK;
234 };
235 auto output = [context](napi_env env, napi_value &result) {
236 result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result);
237 CHECK_RETURN_SET_E(context->intOutput == OK, std::make_shared<InnerError>(context->intOutput));
238 };
239 context->SetAction(env, info, input, exec, output);
240 CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
241 return ASYNC_CALL(env, context);
242 }
243
CreateTransaction(napi_env env,napi_callback_info info)244 napi_value GdbStoreProxy::CreateTransaction(napi_env env, napi_callback_info info)
245 {
246 DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
247 auto context = std::make_shared<CreateTransactionContext>();
248 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
249 CHECK_RETURN_SET_E(argc == 0, std::make_shared<ParamNumError>(" 0 "));
250 CHECK_RETURN(OK == ParseThis(env, self, context));
251 };
252 auto exec = [context]() -> int {
253 CHECK_RETURN_ERR(context->gdbStore != nullptr);
254 int32_t code = E_ERROR;
255 std::tie(code, context->transaction) = context->StealGdbStore()->CreateTransaction();
256 if (code != E_OK) {
257 context->transaction = nullptr;
258 return code;
259 }
260 return context->transaction != nullptr ? OK : E_ERROR;
261 };
262 auto output = [context](napi_env env, napi_value &result) {
263 result = GdbTransactionProxy::NewInstance(env, context->transaction);
264 CHECK_RETURN_SET_E(result != nullptr, std::make_shared<InnerError>(E_INNER_ERROR));
265 };
266 context->SetAction(env, info, input, exec, output);
267 CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
268 return ASYNC_CALL(env, context);
269 }
270
Close(napi_env env,napi_callback_info info)271 napi_value GdbStoreProxy::Close(napi_env env, napi_callback_info info)
272 {
273 DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
274 auto context = std::make_shared<GdbStoreContext>();
275 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
276 GdbStoreProxy *proxy = GetNativeInstance(env, self);
277 CHECK_RETURN_SET(proxy != nullptr, std::make_shared<ParamError>("GdbStore", "not nullptr."));
278 if (proxy->GetInstance() == nullptr) {
279 LOG_WARN("GdbStoreProxy native instance is nullptr!");
280 return OK;
281 }
282 context->boundObj = proxy;
283 context->gdbStore = proxy->GetInstance();
284
285 auto *obj = reinterpret_cast<GdbStoreProxy *>(context->boundObj);
286 obj->SetInstance(nullptr);
287 return OK;
288 };
289 auto exec = [context]() -> int {
290 context->gdbStore = nullptr;
291 return OK;
292 };
293 auto output = [context](napi_env env, napi_value &result) {
294 napi_status status = napi_get_undefined(env, &result);
295 CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
296 };
297 context->SetAction(env, info, input, exec, output);
298 CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
299 return ASYNC_CALL(env, context);
300 }
301 } // namespace OHOS::GraphStoreJsKit