1 /*
2 * Copyright (c) 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 #define LOG_TAG "JsSingleKVStore"
16 #include "js_single_kv_store.h"
17 #include "js_util.h"
18 #include "js_kv_store_resultset.h"
19 #include "datashare_predicates.h"
20 #include "js_query.h"
21 #include "log_print.h"
22 #include "napi_queue.h"
23 #include "uv_queue.h"
24 #include "kv_utils.h"
25
26 using namespace OHOS::DistributedKv;
27 using namespace OHOS::DataShare;
28 namespace OHOS::DistributedKVStore {
29
30 std::map<std::string, JsSingleKVStore::Exec> JsSingleKVStore::onEventHandlers_ = {
31 { "dataChange", JsSingleKVStore::OnDataChange },
32 { "syncComplete", JsSingleKVStore::OnSyncComplete }
33 };
34
35 std::map<std::string, JsSingleKVStore::Exec> JsSingleKVStore::offEventHandlers_ = {
36 { "dataChange", JsSingleKVStore::OffDataChange },
37 { "syncComplete", JsSingleKVStore::OffSyncComplete }
38 };
39
40 std::map<napi_valuetype, std::string> JsSingleKVStore::valueTypeToString_ = {
41 { napi_string, std::string("string") },
42 { napi_number, std::string("integer") },
43 { napi_object, std::string("bytearray") },
44 { napi_boolean, std::string("bollean") },
45 };
46
ValidSubscribeType(uint8_t type)47 static bool ValidSubscribeType(uint8_t type)
48 {
49 return (SUBSCRIBE_LOCAL <= type) && (type <= SUBSCRIBE_LOCAL_REMOTE);
50 }
51
ToSubscribeType(uint8_t type)52 static SubscribeType ToSubscribeType(uint8_t type)
53 {
54 return static_cast<SubscribeType>(type + 1);
55 }
56
JsSingleKVStore(const std::string & storeId)57 JsSingleKVStore::JsSingleKVStore(const std::string& storeId)
58 : storeId_(storeId)
59 {
60 }
61
SetKvStorePtr(std::shared_ptr<SingleKvStore> kvStore)62 void JsSingleKVStore::SetKvStorePtr(std::shared_ptr<SingleKvStore> kvStore)
63 {
64 kvStore_ = kvStore;
65 }
66
GetKvStorePtr()67 std::shared_ptr<SingleKvStore> JsSingleKVStore::GetKvStorePtr()
68 {
69 return kvStore_;
70 }
71
SetContextParam(std::shared_ptr<ContextParam> param)72 void JsSingleKVStore::SetContextParam(std::shared_ptr<ContextParam> param)
73 {
74 param_ = param;
75 }
76
SetUvQueue(std::shared_ptr<UvQueue> uvQueue)77 void JsSingleKVStore::SetUvQueue(std::shared_ptr<UvQueue> uvQueue)
78 {
79 uvQueue_ = uvQueue;
80 }
81
IsSchemaStore() const82 bool JsSingleKVStore::IsSchemaStore() const
83 {
84 return isSchemaStore_;
85 }
86
SetSchemaInfo(bool isSchemaStore)87 void JsSingleKVStore::SetSchemaInfo(bool isSchemaStore)
88 {
89 isSchemaStore_ = isSchemaStore;
90 }
91
IsSystemApp() const92 bool JsSingleKVStore::IsSystemApp() const
93 {
94 return param_->isSystemApp;
95 }
96
~JsSingleKVStore()97 JsSingleKVStore::~JsSingleKVStore()
98 {
99 ZLOGD("no memory leak for JsSingleKVStore");
100 if (kvStore_ == nullptr) {
101 return;
102 }
103
104 std::lock_guard<std::mutex> lck(listMutex_);
105 for (uint8_t type = SUBSCRIBE_LOCAL; type < SUBSCRIBE_COUNT; type++) {
106 for (auto& observer : dataObserver_[type]) {
107 auto subscribeType = ToSubscribeType(type);
108 kvStore_->UnSubscribeKvStore(subscribeType, observer);
109 observer->Clear();
110 }
111 dataObserver_[type].clear();
112 }
113
114 kvStore_->UnRegisterSyncCallback();
115 for (auto &syncObserver : syncObservers_) {
116 syncObserver->Clear();
117 }
118 syncObservers_.clear();
119 }
120
Constructor(napi_env env)121 napi_value JsSingleKVStore::Constructor(napi_env env)
122 {
123 auto lambda = []() -> std::vector<napi_property_descriptor> {
124 std::vector<napi_property_descriptor> properties = {
125 DECLARE_NAPI_FUNCTION("put", JsSingleKVStore::Put),
126 DECLARE_NAPI_FUNCTION("delete", JsSingleKVStore::Delete),
127 DECLARE_NAPI_FUNCTION("putBatch", JsSingleKVStore::PutBatch),
128 DECLARE_NAPI_FUNCTION("deleteBatch", JsSingleKVStore::DeleteBatch),
129 DECLARE_NAPI_FUNCTION("startTransaction", JsSingleKVStore::StartTransaction),
130 DECLARE_NAPI_FUNCTION("commit", JsSingleKVStore::Commit),
131 DECLARE_NAPI_FUNCTION("rollback", JsSingleKVStore::Rollback),
132 DECLARE_NAPI_FUNCTION("enableSync", JsSingleKVStore::EnableSync),
133 DECLARE_NAPI_FUNCTION("setSyncRange", JsSingleKVStore::SetSyncRange),
134 DECLARE_NAPI_FUNCTION("backup", JsSingleKVStore::Backup),
135 DECLARE_NAPI_FUNCTION("restore", JsSingleKVStore::Restore),
136 DECLARE_NAPI_FUNCTION("deleteBackup", JsSingleKVStore::DeleteBackup),
137
138 DECLARE_NAPI_FUNCTION("get", JsSingleKVStore::Get),
139 DECLARE_NAPI_FUNCTION("getEntries", JsSingleKVStore::GetEntries),
140 DECLARE_NAPI_FUNCTION("getResultSet", JsSingleKVStore::GetResultSet),
141 DECLARE_NAPI_FUNCTION("closeResultSet", JsSingleKVStore::CloseResultSet),
142 DECLARE_NAPI_FUNCTION("getResultSize", JsSingleKVStore::GetResultSize),
143 DECLARE_NAPI_FUNCTION("removeDeviceData", JsSingleKVStore::RemoveDeviceData),
144 DECLARE_NAPI_FUNCTION("sync", JsSingleKVStore::Sync),
145 DECLARE_NAPI_FUNCTION("setSyncParam", JsSingleKVStore::SetSyncParam),
146 DECLARE_NAPI_FUNCTION("getSecurityLevel", JsSingleKVStore::GetSecurityLevel),
147 DECLARE_NAPI_FUNCTION("on", JsSingleKVStore::OnEvent), /* same to JsDeviceKVStore */
148 DECLARE_NAPI_FUNCTION("off", JsSingleKVStore::OffEvent) /* same to JsDeviceKVStore */
149 };
150 return properties;
151 };
152 return JSUtil::DefineClass(env, "ohos.data.distributedKVStore", "SingleKVStore", lambda, JsSingleKVStore::New);
153 }
154
155 /*
156 * [JS API Prototype]
157 * [AsyncCallback]
158 * put(key:string, value:Uint8Array | string | boolean | number, callback: AsyncCallback<void>):void;
159 * [Promise]
160 * put(key:string, value:Uint8Array | string | boolean | number):Promise<void>;
161 */
Put(napi_env env,napi_callback_info info)162 napi_value JsSingleKVStore::Put(napi_env env, napi_callback_info info)
163 {
164 struct PutContext : public ContextBase {
165 std::string key;
166 JSUtil::KvStoreVariant value;
167 };
168 auto ctxt = std::make_shared<PutContext>();
169 ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value* argv) {
170 // required 2 arguments :: <key> <value>
171 ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
172 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->key);
173 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "The type of key must be string.");
174 ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->value);
175 if (ctxt->status != napi_ok) {
176 ctxt->isThrowError = true;
177 napi_valuetype ntype = napi_undefined;
178 napi_typeof(env, argv[0], &ntype);
179 auto type = valueTypeToString_.find(ntype);
180 ThrowNapiError(env, Status::INVALID_ARGUMENT, "The type of value must be " + type->second);
181 return;
182 }
183 });
184 ASSERT_NULL(!ctxt->isThrowError, "Put exit");
185
186 auto execute = [ctxt]() {
187 DistributedKv::Key key(ctxt->key);
188 bool isSchemaStore = reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSchemaStore();
189 auto &kvStore = reinterpret_cast<JsSingleKVStore *>(ctxt->native)->kvStore_;
190 DistributedKv::Value value = isSchemaStore ? DistributedKv::Blob(std::get<std::string>(ctxt->value))
191 : JSUtil::VariantValue2Blob(ctxt->value);
192 Status status = kvStore->Put(key, value);
193 ZLOGD("kvStore->Put return %{public}d", status);
194 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
195 napi_ok : napi_generic_failure;
196 };
197 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
198 }
199
200 /*
201 * [JS API Prototype]
202 * [AsyncCallback]
203 * delete(key: string, callback: AsyncCallback<void>): void;
204 * [Promise]
205 * delete(key: string): Promise<void>;
206 */
Delete(napi_env env,napi_callback_info info)207 napi_value JsSingleKVStore::Delete(napi_env env, napi_callback_info info)
208 {
209 struct DeleteContext : public ContextBase {
210 std::string key;
211 std::vector<DistributedKv::Blob> keys;
212 napi_valuetype type;
213 };
214 auto ctxt = std::make_shared<DeleteContext>();
215 ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value* argv) {
216 // required 1 arguments :: <key> || <predicates>
217 ASSERT_BUSINESS_ERR(ctxt, argc == 1, Status::INVALID_ARGUMENT, "The number of parameter is incorrect.");
218 ctxt->type = napi_undefined;
219 ctxt->status = napi_typeof(env, argv[0], &(ctxt->type));
220 if (ctxt->type == napi_string) {
221 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->key);
222 ZLOGD("kvStore->Delete %{public}.6s status:%{public}d", ctxt->key.c_str(), ctxt->status);
223 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
224 "The type of key must be string.");
225 } else if (ctxt->type == napi_object) {
226 JSUtil::StatusMsg statusMsg = JSUtil::GetValue(env, argv[0], ctxt->keys);
227 ctxt->status = statusMsg.status;
228 ZLOGD("kvStore->Delete status:%{public}d", ctxt->status);
229 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
230 "The parameters predicates is incorrect.");
231 ASSERT_PERMISSION_ERR(ctxt,
232 !JSUtil::IsSystemApi(statusMsg.jsApiType) ||
233 reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSystemApp(), Status::PERMISSION_DENIED, "");
234 }
235 });
236 ASSERT_NULL(!ctxt->isThrowError, "Delete exit");
237
238 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), [ctxt]() {
239 Status status = Status::INVALID_ARGUMENT;
240 if (ctxt->type == napi_string) {
241 OHOS::DistributedKv::Key key(ctxt->key);
242 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
243 status = kvStore->Delete(key);
244 ZLOGD("kvStore->Delete %{public}.6s status:%{public}d", ctxt->key.c_str(), status);
245 } else if (ctxt->type == napi_object) {
246 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
247 status = kvStore->DeleteBatch(ctxt->keys);
248 ZLOGD("kvStore->DeleteBatch status:%{public}d", status);
249 }
250 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
251 napi_ok : napi_generic_failure;
252 });
253 }
254
255 /*
256 * [JS API Prototype]
257 * [Callback]
258 * on(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
259 * on(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
260 */
OnEvent(napi_env env,napi_callback_info info)261 napi_value JsSingleKVStore::OnEvent(napi_env env, napi_callback_info info)
262 {
263 auto ctxt = std::make_shared<ContextBase>();
264 auto input = [env, ctxt](size_t argc, napi_value* argv) {
265 // required 2 arguments :: <event> [...] <callback>
266 ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
267 std::string event;
268 ctxt->status = JSUtil::GetValue(env, argv[0], event);
269 ZLOGI("subscribe to event:%{public}s", event.c_str());
270 auto handle = onEventHandlers_.find(event);
271 ASSERT_BUSINESS_ERR(ctxt, handle != onEventHandlers_.end(), Status::INVALID_ARGUMENT,
272 "The type of parameters event is incorrect.");
273 // shift 1 argument, for JsSingleKVStore::Exec.
274 handle->second(env, argc - 1, &argv[1], ctxt);
275 };
276 ctxt->GetCbInfoSync(env, info, input);
277 ASSERT_NULL(!ctxt->isThrowError, "OnEvent exit");
278 if (ctxt->status != napi_ok) {
279 ThrowNapiError(env, Status::INVALID_ARGUMENT, "");
280 }
281 return nullptr;
282 }
283
284 /*
285 * [JS API Prototype]
286 * [Callback]
287 * off(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
288 * off(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
289 */
OffEvent(napi_env env,napi_callback_info info)290 napi_value JsSingleKVStore::OffEvent(napi_env env, napi_callback_info info)
291 {
292 auto ctxt = std::make_shared<ContextBase>();
293 auto input = [env, ctxt](size_t argc, napi_value* argv) {
294 // required 1 arguments :: <event> [callback]
295 ASSERT_BUSINESS_ERR(ctxt, argc != 0, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
296 std::string event;
297 ctxt->status = JSUtil::GetValue(env, argv[0], event);
298 ZLOGI("unsubscribe to event:%{public}s", event.c_str());
299 auto handle = offEventHandlers_.find(event);
300 ASSERT_BUSINESS_ERR(ctxt, handle != offEventHandlers_.end(), Status::INVALID_ARGUMENT,
301 "The type of parameters event is incorrect.");
302 // shift 1 argument, for JsSingleKVStore::Exec.
303 handle->second(env, argc - 1, &argv[1], ctxt);
304 };
305 ctxt->GetCbInfoSync(env, info, input);
306 ASSERT_NULL(!ctxt->isThrowError, "OffEvent exit");
307 if (ctxt->status != napi_ok) {
308 ThrowNapiError(env, Status::INVALID_ARGUMENT, "");
309 }
310 return nullptr;
311 }
312
313 /*
314 * [JS API Prototype]
315 * [AsyncCallback]
316 * putBatch(entries: Entry[], callback: AsyncCallback<void>):void;
317 * putBatch(valuesBucket: ValuesBucket[], callback: AsyncCallback<void>): void;
318 * [Promise]
319 * putBatch(entries: Entry[]):Promise<void>;
320 * putBatch(valuesBuckets: ValuesBucket[]): Promise<void>;
321 */
PutBatch(napi_env env,napi_callback_info info)322 napi_value JsSingleKVStore::PutBatch(napi_env env, napi_callback_info info)
323 {
324 struct PutBatchContext : public ContextBase {
325 std::vector<Entry> entries;
326 };
327 auto ctxt = std::make_shared<PutBatchContext>();
328 ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
329 // required 1 arguments :: <entries>
330 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
331 auto isSchemaStore = reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSchemaStore();
332 JSUtil::StatusMsg statusMsg = JSUtil::GetValue(env, argv[0], ctxt->entries, isSchemaStore);
333 ctxt->status = statusMsg.status;
334 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
335 "The type of entries is incorrect.");
336 ASSERT_PERMISSION_ERR(ctxt,
337 !JSUtil::IsSystemApi(statusMsg.jsApiType) ||
338 reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSystemApp(), Status::PERMISSION_DENIED, "");
339 });
340 ASSERT_NULL(!ctxt->isThrowError, "PutBatch exit");
341
342 auto execute = [ctxt]() {
343 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
344 Status status = kvStore->PutBatch(ctxt->entries);
345 ZLOGD("kvStore->DeleteBatch return %{public}d", status);
346 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
347 napi_ok : napi_generic_failure;
348 };
349 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
350 }
351
352 /*
353 * [JS API Prototype]
354 * [AsyncCallback]
355 * deleteBatch(keys: string[], callback: AsyncCallback<void>):void;
356 * [Promise]
357 * deleteBatch(keys: string[]):Promise<void>;
358 */
DeleteBatch(napi_env env,napi_callback_info info)359 napi_value JsSingleKVStore::DeleteBatch(napi_env env, napi_callback_info info)
360 {
361 struct DeleteBatchContext : public ContextBase {
362 std::vector<std::string> keys;
363 };
364 auto ctxt = std::make_shared<DeleteBatchContext>();
365 auto input = [env, ctxt](size_t argc, napi_value* argv) {
366 // required 1 arguments :: <keys>
367 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
368 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->keys);
369 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "The type of keys is incorrect.");
370 };
371 ctxt->GetCbInfo(env, info, input);
372 ASSERT_NULL(!ctxt->isThrowError, "DeleteBatch exit");
373
374 auto execute = [ctxt]() {
375 std::vector<DistributedKv::Key> keys;
376 for (auto it : ctxt->keys) {
377 DistributedKv::Key key(it);
378 keys.push_back(key);
379 }
380 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
381 Status status = kvStore->DeleteBatch(keys);
382 ZLOGD("kvStore->DeleteBatch return %{public}d", status);
383 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
384 napi_ok : napi_generic_failure;
385 };
386 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
387 }
388
389 /*
390 * [JS API Prototype]
391 * [AsyncCallback]
392 * startTransaction(callback: AsyncCallback<void>):void;
393 * [Promise]
394 * startTransaction() : Promise<void>;
395 */
StartTransaction(napi_env env,napi_callback_info info)396 napi_value JsSingleKVStore::StartTransaction(napi_env env, napi_callback_info info)
397 {
398 auto ctxt = std::make_shared<ContextBase>();
399 ctxt->GetCbInfo(env, info);
400 auto execute = [ctxt]() {
401 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
402 Status status = kvStore->StartTransaction();
403 ZLOGD("kvStore->StartTransaction return %{public}d", status);
404 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
405 napi_ok : napi_generic_failure;
406 };
407 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
408 }
409
410 /*
411 * [JS API Prototype]
412 * [AsyncCallback]
413 * commit(callback: AsyncCallback<void>):void;
414 * [Promise]
415 * commit() : Promise<void>;
416 */
Commit(napi_env env,napi_callback_info info)417 napi_value JsSingleKVStore::Commit(napi_env env, napi_callback_info info)
418 {
419 auto ctxt = std::make_shared<ContextBase>();
420 ctxt->GetCbInfo(env, info);
421
422 auto execute = [ctxt]() {
423 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
424 Status status = kvStore->Commit();
425 ZLOGD("kvStore->Commit return %{public}d", status);
426 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
427 napi_ok : napi_generic_failure;
428 };
429 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
430 }
431
432 /*
433 * [JS API Prototype]
434 * [AsyncCallback]
435 * rollback(callback: AsyncCallback<void>):void;
436 * [Promise]
437 * rollback() : Promise<void>;
438 */
Rollback(napi_env env,napi_callback_info info)439 napi_value JsSingleKVStore::Rollback(napi_env env, napi_callback_info info)
440 {
441 auto ctxt = std::make_shared<ContextBase>();
442 ctxt->GetCbInfo(env, info);
443
444 auto execute = [ctxt]() {
445 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
446 Status status = kvStore->Rollback();
447 ZLOGD("kvStore->Commit return %{public}d", status);
448 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
449 napi_ok : napi_generic_failure;
450 };
451 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
452 }
453
454 /*
455 * [JS API Prototype]
456 * [AsyncCallback]
457 * enableSync(enabled:boolean, callback: AsyncCallback<void>):void;
458 * [Promise]
459 * enableSync(enabled:boolean) : Promise<void>;
460 */
EnableSync(napi_env env,napi_callback_info info)461 napi_value JsSingleKVStore::EnableSync(napi_env env, napi_callback_info info)
462 {
463 struct EnableSyncContext : public ContextBase {
464 bool enable = false;
465 };
466 auto ctxt = std::make_shared<EnableSyncContext>();
467 auto input = [env, ctxt](size_t argc, napi_value* argv) {
468 // required 1 arguments :: <enable>
469 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
470 ctxt->status = napi_get_value_bool(env, argv[0], &ctxt->enable);
471 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
472 "The parameters of enable is incorrect.");
473 };
474 ctxt->GetCbInfo(env, info, input);
475 ASSERT_NULL(!ctxt->isThrowError, "EnableSync exit");
476
477 auto execute = [ctxt]() {
478 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
479 Status status = kvStore->SetCapabilityEnabled(ctxt->enable);
480 ZLOGD("kvStore->SetCapabilityEnabled return %{public}d", status);
481 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
482 napi_ok : napi_generic_failure;
483 };
484 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
485 }
486
487 /*
488 * [JS API Prototype]
489 * [AsyncCallback]
490 * setSyncRange(localLabels:string[], remoteSupportLabels:string[], callback: AsyncCallback<void>):void;
491 * [Promise]
492 * setSyncRange(localLabels:string[], remoteSupportLabels:string[]) : Promise<void>;
493 */
SetSyncRange(napi_env env,napi_callback_info info)494 napi_value JsSingleKVStore::SetSyncRange(napi_env env, napi_callback_info info)
495 {
496 struct SyncRangeContext : public ContextBase {
497 std::vector<std::string> localLabels;
498 std::vector<std::string> remoteSupportLabels;
499 };
500 auto ctxt = std::make_shared<SyncRangeContext>();
501 auto input = [env, ctxt](size_t argc, napi_value* argv) {
502 // required 2 arguments :: <localLabels> <remoteSupportLabels>
503 ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
504 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->localLabels);
505 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
506 "The type of parameter localLabels is string array.");
507 ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->remoteSupportLabels);
508 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
509 "The type of parameter remoteSupportLabels is string array.");
510 };
511 ctxt->GetCbInfo(env, info, input);
512 ASSERT_NULL(!ctxt->isThrowError, "SetSyncRange exit");
513
514 auto execute = [ctxt]() {
515 auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
516 Status status = kvStore->SetCapabilityRange(ctxt->localLabels, ctxt->remoteSupportLabels);
517 ZLOGD("kvStore->SetCapabilityRange return %{public}d", status);
518 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
519 napi_ok : napi_generic_failure;
520 };
521 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
522 }
523
524 /*
525 * [JS API Prototype]
526 * [AsyncCallback]
527 * backup(file:string, callback: AsyncCallback<void>):void;
528 * [Promise]
529 * backup(file:string): Promise<void>;
530 */
Backup(napi_env env,napi_callback_info info)531 napi_value JsSingleKVStore::Backup(napi_env env, napi_callback_info info)
532 {
533 struct BackupContext : public ContextBase {
534 std::string file;
535 };
536 auto ctxt = std::make_shared<BackupContext>();
537 auto input = [env, ctxt](size_t argc, napi_value* argv) {
538 // required 1 arguments :: <file>
539 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
540 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->file);
541 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
542 "The type of parameter file is string.");
543 };
544 ctxt->GetCbInfo(env, info, input);
545 ASSERT_NULL(!ctxt->isThrowError, "Backup exit");
546
547 auto execute = [ctxt]() {
548 auto jsKvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
549 Status status = jsKvStore->kvStore_->Backup(ctxt->file, jsKvStore->param_->baseDir);
550 ZLOGD("kvStore->Backup return %{public}d", status);
551 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
552 napi_ok : napi_generic_failure;
553 };
554 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
555 }
556
557 /*
558 * [JS API Prototype]
559 * [AsyncCallback]
560 * restore(file:string, callback: AsyncCallback<void>):void;
561 * [Promise]
562 * restore(file:string): Promise<void>;
563 */
Restore(napi_env env,napi_callback_info info)564 napi_value JsSingleKVStore::Restore(napi_env env, napi_callback_info info)
565 {
566 struct RestoreContext : public ContextBase {
567 std::string file;
568 };
569 auto ctxt = std::make_shared<RestoreContext>();
570 auto input = [env, ctxt](size_t argc, napi_value* argv) {
571 // required 1 arguments :: <file>
572 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
573 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->file);
574 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
575 "The type of parameter file is string.");
576 };
577 ctxt->GetCbInfo(env, info, input);
578 ASSERT_NULL(!ctxt->isThrowError, "Restore exit");
579
580 auto execute = [ctxt]() {
581 auto jsKvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
582 Status status = jsKvStore->kvStore_->Restore(ctxt->file, jsKvStore->param_->baseDir);
583 ZLOGD("kvStore->Restore return %{public}d", status);
584 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
585 napi_ok : napi_generic_failure;
586 };
587 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
588 }
589
590 /*
591 * [JS API Prototype]
592 * [AsyncCallback]
593 * deleteBackup(files:Array<string>, callback: AsyncCallback<Array<[string, number]>>):void;
594 * [Promise]
595 * deleteBackup(files:Array<string>): Promise<Array<[string, number]>>;
596 */
DeleteBackup(napi_env env,napi_callback_info info)597 napi_value JsSingleKVStore::DeleteBackup(napi_env env, napi_callback_info info)
598 {
599 struct DeleteBackupContext : public ContextBase {
600 std::vector<std::string> files;
601 std::map<std::string, DistributedKv::Status> results;
602 };
603 auto ctxt = std::make_shared<DeleteBackupContext>();
604 auto input = [env, ctxt](size_t argc, napi_value* argv) {
605 // required 1 arguments :: <files>
606 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
607 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->files);
608 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
609 "The type of parameter file is string.");
610 };
611 ctxt->GetCbInfo(env, info, input);
612 ASSERT_NULL(!ctxt->isThrowError, "DeleteBackup exit");
613
614 auto execute = [ctxt]() {
615 auto jsKvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
616 Status status = jsKvStore->kvStore_->DeleteBackup(ctxt->files,
617 jsKvStore->param_->baseDir, ctxt->results);
618 ZLOGD("kvStore->DeleteBackup return %{public}d", status);
619 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
620 napi_ok : napi_generic_failure;
621 };
622 auto output = [env, ctxt](napi_value& result) {
623 ctxt->status = JSUtil::SetValue(env, ctxt->results, result);
624 ASSERT_STATUS(ctxt, "output failed!");
625 };
626 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
627 }
628
629 /*
630 * [JS API Prototype] JsSingleKVStore::OnDataChange is private non-static.
631 * [Callback]
632 * on(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
633 */
OnDataChange(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)634 void JsSingleKVStore::OnDataChange(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
635 {
636 // required 2 arguments :: <SubscribeType> <observer>
637 ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
638
639 int32_t type = SUBSCRIBE_COUNT;
640 ctxt->status = napi_get_value_int32(env, argv[0], &type);
641 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "");
642 ASSERT_BUSINESS_ERR(ctxt, ValidSubscribeType(type), Status::INVALID_ARGUMENT,
643 "The type of parameter event is incorrect.");
644
645 napi_valuetype valueType = napi_undefined;
646 ctxt->status = napi_typeof(env, argv[1], &valueType);
647 ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
648 "The type of parameter Callback is incorrect.");
649
650 ZLOGI("subscribe data change type %{public}d", type);
651 auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
652 std::lock_guard<std::mutex> lck(proxy->listMutex_);
653 for (auto& it : proxy->dataObserver_[type]) {
654 if (JSUtil::Equals(env, argv[1], it->GetCallback())) {
655 ZLOGI("function is already subscribe type");
656 return;
657 }
658 }
659
660 Status status = proxy->Subscribe(type,
661 std::make_shared<DataObserver>(proxy->uvQueue_, argv[1], proxy->IsSchemaStore()));
662 ThrowNapiError(env, status, "", false);
663 }
664
665 /*
666 * [JS API Prototype] JsSingleKVStore::OffDataChange is private non-static.
667 * [Callback]
668 * on(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
669 * [NOTES!!!] no SubscribeType while off...
670 * off(event:'dataChange', observer: Callback<ChangeNotification>): void;
671 */
OffDataChange(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)672 void JsSingleKVStore::OffDataChange(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
673 {
674 // required 1 arguments :: [callback]
675 ASSERT_BUSINESS_ERR(ctxt, argc <= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
676 // have 1 arguments :: have the callback
677 if (argc == 1) {
678 napi_valuetype valueType = napi_undefined;
679 ctxt->status = napi_typeof(env, argv[0], &valueType);
680 ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
681 "The type of parameter Callback is incorrect.");
682 }
683
684 ZLOGI("unsubscribe dataChange, %{public}s specified observer.", (argc == 0) ? "without": "with");
685
686 auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
687 bool found = false;
688 Status status = Status::SUCCESS;
689 auto traverseType = [argc, argv, proxy, env, &found, &status](uint8_t type, auto& observers) {
690 auto it = observers.begin();
691 while (it != observers.end()) {
692 if ((argc == 1) && !JSUtil::Equals(env, argv[0], (*it)->GetCallback())) {
693 ++it;
694 continue; // specified observer and not current iterator
695 }
696 found = true;
697 status = proxy->UnSubscribe(type, *it);
698 if (status != Status::SUCCESS) {
699 break; // stop on fail.
700 }
701 it = observers.erase(it);
702 }
703 };
704
705 std::lock_guard<std::mutex> lck(proxy->listMutex_);
706 for (uint8_t type = SUBSCRIBE_LOCAL; type < SUBSCRIBE_COUNT; type++) {
707 traverseType(type, proxy->dataObserver_[type]);
708 if (status != Status::SUCCESS) {
709 break; // stop on fail.
710 }
711 }
712 ASSERT_BUSINESS_ERR(ctxt, found || (argc == 0), Status::INVALID_ARGUMENT, "not Subscribed!");
713 ThrowNapiError(env, status, "", false);
714 }
715
716 /*
717 * [JS API Prototype] JsSingleKVStore::OnSyncComplete is private non-static.
718 * [Callback]
719 * on(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
720 */
OnSyncComplete(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)721 void JsSingleKVStore::OnSyncComplete(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
722 {
723 // required 1 arguments :: <callback>
724 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
725 napi_valuetype valueType = napi_undefined;
726 ctxt->status = napi_typeof(env, argv[0], &valueType);
727 ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
728 "The type of parameter Callback is incorrect.");
729
730 auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
731 ctxt->status = proxy->RegisterSyncCallback(std::make_shared<SyncObserver>(proxy->uvQueue_, argv[0]));
732 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "RegisterSyncCallback failed!");
733 }
734
735 /*
736 * [JS API Prototype] JsSingleKVStore::OffSyncComplete is private non-static.
737 * [Callback]
738 * off(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
739 */
OffSyncComplete(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)740 void JsSingleKVStore::OffSyncComplete(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
741 {
742 // required 1 arguments :: [callback]
743 auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
744 // have 1 arguments :: have the callback
745 if (argc == 1) {
746 napi_valuetype valueType = napi_undefined;
747 ctxt->status = napi_typeof(env, argv[0], &valueType);
748 ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
749 "The type of parameter Callback is incorrect.");
750 std::lock_guard<std::mutex> lck(proxy->listMutex_);
751 auto it = proxy->syncObservers_.begin();
752 while (it != proxy->syncObservers_.end()) {
753 if (JSUtil::Equals(env, argv[0], (*it)->GetCallback())) {
754 (*it)->Clear();
755 proxy->syncObservers_.erase(it);
756 break;
757 }
758 }
759 ctxt->status = napi_ok;
760 }
761 ZLOGI("unsubscribe syncComplete, %{public}s specified observer.", (argc == 0) ? "without": "with");
762 if (argc == 0 || proxy->syncObservers_.empty()) {
763 ctxt->status = proxy->UnRegisterSyncCallback();
764 }
765 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "UnRegisterSyncCallback failed!");
766 }
767
768 /*
769 * [Internal private non-static]
770 */
RegisterSyncCallback(std::shared_ptr<SyncObserver> callback)771 napi_status JsSingleKVStore::RegisterSyncCallback(std::shared_ptr<SyncObserver> callback)
772 {
773 Status status = kvStore_->RegisterSyncCallback(callback);
774 if (status != Status::SUCCESS) {
775 callback->Clear();
776 return napi_generic_failure;
777 }
778 std::lock_guard<std::mutex> lck(listMutex_);
779 syncObservers_.push_back(callback);
780 return napi_ok;
781 }
782
UnRegisterSyncCallback()783 napi_status JsSingleKVStore::UnRegisterSyncCallback()
784 {
785 Status status = kvStore_->UnRegisterSyncCallback();
786 if (status != Status::SUCCESS) {
787 return napi_generic_failure;
788 }
789 std::lock_guard<std::mutex> lck(listMutex_);
790 for (auto &syncObserver : syncObservers_) {
791 syncObserver->Clear();
792 }
793 syncObservers_.clear();
794 return napi_ok;
795 }
796
Subscribe(uint8_t type,std::shared_ptr<DataObserver> observer)797 Status JsSingleKVStore::Subscribe(uint8_t type, std::shared_ptr<DataObserver> observer)
798 {
799 auto subscribeType = ToSubscribeType(type);
800 Status status = kvStore_->SubscribeKvStore(subscribeType, observer);
801 ZLOGD("kvStore_->SubscribeKvStore(%{public}d) return %{public}d", type, status);
802 if (status != Status::SUCCESS) {
803 observer->Clear();
804 return status;
805 }
806 dataObserver_[type].push_back(observer);
807 return status;
808 }
809
UnSubscribe(uint8_t type,std::shared_ptr<DataObserver> observer)810 Status JsSingleKVStore::UnSubscribe(uint8_t type, std::shared_ptr<DataObserver> observer)
811 {
812 auto subscribeType = ToSubscribeType(type);
813 Status status = kvStore_->UnSubscribeKvStore(subscribeType, observer);
814 ZLOGD("kvStore_->UnSubscribeKvStore(%{public}d) return %{public}d", type, status);
815 if (status == Status::SUCCESS) {
816 observer->Clear();
817 return status;
818 }
819 return status;
820 }
821
OnChange(const ChangeNotification & notification)822 void JsSingleKVStore::DataObserver::OnChange(const ChangeNotification& notification)
823 {
824 ZLOGD("data change insert:%{public}zu, update:%{public}zu, delete:%{public}zu",
825 notification.GetInsertEntries().size(), notification.GetUpdateEntries().size(),
826 notification.GetDeleteEntries().size());
827 KvStoreObserver::OnChange(notification);
828
829 auto args = [notification, isSchema = isSchema_](napi_env env, int& argc, napi_value* argv) {
830 // generate 1 arguments for callback function.
831 argc = 1;
832 JSUtil::SetValue(env, notification, argv[0], isSchema);
833 };
834 AsyncCall(args);
835 }
836
SyncCompleted(const std::map<std::string,DistributedKv::Status> & results)837 void JsSingleKVStore::SyncObserver::SyncCompleted(const std::map<std::string, DistributedKv::Status>& results)
838 {
839 auto args = [results](napi_env env, int& argc, napi_value* argv) {
840 // generate 1 arguments for callback function.
841 argc = 1;
842 JSUtil::SetValue(env, results, argv[0]);
843 };
844 AsyncCall(args);
845 }
846
847 /*
848 * [JS API Prototype]
849 * [AsyncCallback]
850 * get(key:string, callback:AsyncCallback<boolean|string|number|Uint8Array>):void;
851 * [Promise]
852 * get(key:string):Promise<boolean|string|number|Uint8Array>;
853 */
Get(napi_env env,napi_callback_info info)854 napi_value JsSingleKVStore::Get(napi_env env, napi_callback_info info)
855 {
856 struct GetContext : public ContextBase {
857 std::string key;
858 JSUtil::KvStoreVariant value;
859 };
860 auto ctxt = std::make_shared<GetContext>();
861 auto input = [env, ctxt](size_t argc, napi_value* argv) {
862 // required 1 arguments :: <key>
863 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
864 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->key);
865 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "The type of key must be string.");
866 };
867 ctxt->GetCbInfo(env, info, input);
868 ASSERT_NULL(!ctxt->isThrowError, "Get exit");
869
870 ZLOGD("key=%{public}.8s", ctxt->key.c_str());
871 auto execute = [env, ctxt]() {
872 OHOS::DistributedKv::Key key(ctxt->key);
873 OHOS::DistributedKv::Value value;
874 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
875 bool isSchemaStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->IsSchemaStore();
876 Status status = kvStore->Get(key, value);
877 ZLOGD("kvStore->Get return %{public}d", status);
878 ctxt->value = isSchemaStore ? value.ToString() : JSUtil::Blob2VariantValue(value);
879 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
880 napi_ok : napi_generic_failure;
881 };
882 auto output = [env, ctxt](napi_value& result) {
883 ctxt->status = JSUtil::SetValue(env, ctxt->value, result);
884 ASSERT_STATUS(ctxt, "output failed");
885 };
886 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
887 }
888
889 struct VariantArgs {
890 DataQuery dataQuery;
891 std::string errMsg = "";
892 };
893
GetVariantArgs(napi_env env,size_t argc,napi_value * argv,VariantArgs & va)894 static JSUtil::StatusMsg GetVariantArgs(napi_env env, size_t argc, napi_value* argv, VariantArgs& va)
895 {
896 // required 1 arguments :: <keyPrefix/query>
897 napi_valuetype type = napi_undefined;
898 JSUtil::StatusMsg statusMsg = napi_typeof(env, argv[0], &type);
899 if (statusMsg != napi_ok || (type != napi_string && type != napi_object)) {
900 va.errMsg = "The type of parameters keyPrefix/query is incorrect.";
901 return statusMsg.status != napi_ok ? statusMsg.status : napi_invalid_arg;
902 }
903 if (type == napi_string) {
904 std::string keyPrefix;
905 JSUtil::GetValue(env, argv[0], keyPrefix);
906 if (keyPrefix.empty()) {
907 va.errMsg = "The type of parameters keyPrefix is incorrect.";
908 return napi_invalid_arg;
909 }
910 va.dataQuery.KeyPrefix(keyPrefix);
911 } else if (type == napi_object) {
912 bool result = false;
913 statusMsg = napi_instanceof(env, argv[0], JsQuery::Constructor(env), &result);
914 if ((statusMsg == napi_ok) && (result != false)) {
915 JsQuery *jsQuery = nullptr;
916 statusMsg = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void **>(&jsQuery), JsQuery::Constructor(env));
917 if (jsQuery == nullptr) {
918 va.errMsg = "The parameters query is incorrect.";
919 return napi_invalid_arg;
920 }
921 va.dataQuery = jsQuery->GetDataQuery();
922 } else {
923 statusMsg = JSUtil::GetValue(env, argv[0], va.dataQuery);
924 ZLOGD("kvStoreDataShare->GetResultSet return %{public}d", statusMsg.status);
925 statusMsg.jsApiType = JSUtil::DATASHARE;
926 }
927 }
928 return statusMsg;
929 };
930
931 /*
932 * [JS API Prototype]
933 * getEntries(keyPrefix:string, callback:AsyncCallback<Entry[]>):void
934 * getEntries(keyPrefix:string):Promise<Entry[]>
935 *
936 * getEntries(query:Query, callback:AsyncCallback<Entry[]>):void
937 * getEntries(query:Query) : Promise<Entry[]>
938 */
GetEntries(napi_env env,napi_callback_info info)939 napi_value JsSingleKVStore::GetEntries(napi_env env, napi_callback_info info)
940 {
941 struct GetEntriesContext : public ContextBase {
942 VariantArgs va;
943 std::vector<Entry> entries;
944 };
945 auto ctxt = std::make_shared<GetEntriesContext>();
946 auto input = [env, ctxt](size_t argc, napi_value* argv) {
947 // required 1 arguments :: <keyPrefix/query>
948 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
949 ctxt->status = GetVariantArgs(env, argc, argv, ctxt->va);
950 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, ctxt->va.errMsg);
951 };
952 ctxt->GetCbInfo(env, info, input);
953 ASSERT_NULL(!ctxt->isThrowError, "GetEntries exit");
954
955 auto execute = [ctxt]() {
956 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
957 Status status = kvStore->GetEntries(ctxt->va.dataQuery, ctxt->entries);
958 ZLOGD("kvStore->GetEntries() return %{public}d", status);
959 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
960 napi_ok : napi_generic_failure;
961 };
962 auto output = [env, ctxt](napi_value& result) {
963 auto isSchemaStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->IsSchemaStore();
964 ctxt->status = JSUtil::SetValue(env, ctxt->entries, result, isSchemaStore);
965 ASSERT_STATUS(ctxt, "output failed!");
966 };
967 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
968 }
969
970 /*
971 * [JS API Prototype]
972 * getResultSet(keyPrefix:string, callback:AsyncCallback<KvStoreResultSet>):void
973 * getResultSet(keyPrefix:string):Promise<KvStoreResultSet>
974 *
975 * getResultSet(query:Query, callback:AsyncCallback<KvStoreResultSet>):void
976 * getResultSet(query:Query):Promise<KvStoreResultSet>
977 */
GetResultSet(napi_env env,napi_callback_info info)978 napi_value JsSingleKVStore::GetResultSet(napi_env env, napi_callback_info info)
979 {
980 struct GetResultSetContext : public ContextBase {
981 VariantArgs va;
982 JsKVStoreResultSet* resultSet = nullptr;
983 napi_ref ref = nullptr;
984 };
985 auto ctxt = std::make_shared<GetResultSetContext>();
986 auto input = [env, ctxt](size_t argc, napi_value* argv) {
987 // required 1 arguments :: <keyPrefix/query>
988 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
989 JSUtil::StatusMsg statusMsg = GetVariantArgs(env, argc, argv, ctxt->va);
990 ctxt->status = statusMsg.status;
991 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, ctxt->va.errMsg);
992 ASSERT_PERMISSION_ERR(ctxt,
993 !JSUtil::IsSystemApi(statusMsg.jsApiType) ||
994 reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSystemApp(), Status::PERMISSION_DENIED, "");
995 ctxt->ref = JSUtil::NewWithRef(env, 0, nullptr, reinterpret_cast<void**>(&ctxt->resultSet),
996 JsKVStoreResultSet::Constructor(env));
997 ASSERT_BUSINESS_ERR(ctxt, ctxt->resultSet != nullptr, Status::INVALID_ARGUMENT,
998 "KVStoreResultSet::New failed!");
999 };
1000 ctxt->GetCbInfo(env, info, input);
1001 ASSERT_NULL(!ctxt->isThrowError, "GetResultSet exit");
1002
1003 auto execute = [ctxt]() {
1004 std::shared_ptr<KvStoreResultSet> kvResultSet;
1005 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1006 Status status = kvStore->GetResultSet(ctxt->va.dataQuery, kvResultSet);
1007 ZLOGD("kvStore->GetResultSet() return %{public}d", status);
1008
1009 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1010 napi_ok : napi_generic_failure;
1011 ctxt->resultSet->SetKvStoreResultSetPtr(kvResultSet);
1012 bool isSchema = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->IsSchemaStore();
1013 ctxt->resultSet->SetSchema(isSchema);
1014 };
1015 auto output = [env, ctxt](napi_value& result) {
1016 ctxt->status = napi_get_reference_value(env, ctxt->ref, &result);
1017 napi_delete_reference(env, ctxt->ref);
1018 ASSERT_STATUS(ctxt, "output kvResultSet failed");
1019 };
1020 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
1021 }
1022
1023 /*
1024 * [JS API Prototype]
1025 * closeResultSet(resultSet:KVStoreResultSet, callback: AsyncCallback<void>):void
1026 * closeResultSet(resultSet:KVStoreResultSet):Promise<void>
1027 */
CloseResultSet(napi_env env,napi_callback_info info)1028 napi_value JsSingleKVStore::CloseResultSet(napi_env env, napi_callback_info info)
1029 {
1030 struct CloseResultSetContext : public ContextBase {
1031 JsKVStoreResultSet* resultSet = nullptr;
1032 };
1033 auto ctxt = std::make_shared<CloseResultSetContext>();
1034 auto input = [env, ctxt](size_t argc, napi_value* argv) {
1035 // required 1 arguments :: <resultSet>
1036 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
1037 napi_valuetype type = napi_undefined;
1038 ctxt->status = napi_typeof(env, argv[0], &type);
1039 ASSERT_BUSINESS_ERR(ctxt, type == napi_object, Status::INVALID_ARGUMENT,
1040 "The type of parameters resultSet is incorrect.");
1041 ctxt->status = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void**>(&ctxt->resultSet),
1042 JsKVStoreResultSet::Constructor(env));
1043 ASSERT_BUSINESS_ERR(ctxt, ctxt->resultSet != nullptr, Status::INVALID_ARGUMENT,
1044 "The parameters resultSet is incorrect.");
1045 };
1046 ctxt->GetCbInfo(env, info, input);
1047 ASSERT_NULL(!ctxt->isThrowError, "CloseResultSet exit");
1048
1049 auto execute = [ctxt]() {
1050 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1051 auto resultSet = ctxt->resultSet->GetKvStoreResultSetPtr();
1052 Status status = kvStore->CloseResultSet(resultSet);
1053 ZLOGD("kvStore->CloseResultSet return %{public}d", status);
1054 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1055 napi_ok : napi_generic_failure;
1056 };
1057 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
1058 }
1059
1060 /*
1061 * [JS API Prototype]
1062 * getResultSize(query:Query, callback: AsyncCallback<number>):void
1063 * getResultSize(query:Query):Promise<number>
1064 */
GetResultSize(napi_env env,napi_callback_info info)1065 napi_value JsSingleKVStore::GetResultSize(napi_env env, napi_callback_info info)
1066 {
1067 struct ResultSizeContext : public ContextBase {
1068 JsQuery* query = nullptr;
1069 int resultSize = 0;
1070 };
1071 auto ctxt = std::make_shared<ResultSizeContext>();
1072 auto input = [env, ctxt](size_t argc, napi_value* argv) {
1073 // required 1 arguments :: <query>
1074 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
1075 napi_valuetype type = napi_undefined;
1076 ctxt->status = napi_typeof(env, argv[0], &type);
1077 ASSERT_BUSINESS_ERR(ctxt, type == napi_object, Status::INVALID_ARGUMENT,
1078 "The type of parameters query is incorrect.");
1079 ctxt->status = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void**>(&ctxt->query), JsQuery::Constructor(env));
1080 ASSERT_BUSINESS_ERR(ctxt, ctxt->query != nullptr, Status::INVALID_ARGUMENT,
1081 "The parameters query is incorrect.");
1082 };
1083 ctxt->GetCbInfo(env, info, input);
1084 ASSERT_NULL(!ctxt->isThrowError, "GetResultSize exit");
1085
1086 auto execute = [ctxt]() {
1087 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1088 auto query = ctxt->query->GetDataQuery();
1089 Status status = kvStore->GetCount(query, ctxt->resultSize);
1090 ZLOGD("kvStore->GetCount() return %{public}d", status);
1091 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1092 napi_ok : napi_generic_failure;
1093 };
1094 auto output = [env, ctxt](napi_value& result) {
1095 ctxt->status = JSUtil::SetValue(env, static_cast<int32_t>(ctxt->resultSize), result);
1096 ASSERT_STATUS(ctxt, "output resultSize failed!");
1097 };
1098 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
1099 }
1100
1101 /*
1102 * [JS API Prototype]
1103 * removeDeviceData(deviceId:string, callback: AsyncCallback<void>):void
1104 * removeDeviceData(deviceId:string):Promise<void>
1105 */
RemoveDeviceData(napi_env env,napi_callback_info info)1106 napi_value JsSingleKVStore::RemoveDeviceData(napi_env env, napi_callback_info info)
1107 {
1108 struct RemoveDeviceContext : public ContextBase {
1109 std::string deviceId;
1110 };
1111 auto ctxt = std::make_shared<RemoveDeviceContext>();
1112 auto input = [env, ctxt](size_t argc, napi_value* argv) {
1113 // required 1 arguments :: <deviceId>
1114 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
1115 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->deviceId);
1116 ASSERT_BUSINESS_ERR(ctxt, (!ctxt->deviceId.empty()) && (ctxt->status == napi_ok), Status::INVALID_ARGUMENT,
1117 "The parameters deviceId is incorrect.");
1118 };
1119 ctxt->GetCbInfo(env, info, input);
1120 ASSERT_NULL(!ctxt->isThrowError, "RemoveDeviceData exit");
1121
1122 auto execute = [ctxt]() {
1123 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1124 Status status = kvStore->RemoveDeviceData(ctxt->deviceId);
1125 ZLOGD("kvStore->RemoveDeviceData return %{public}d", status);
1126 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1127 napi_ok : napi_generic_failure;
1128 };
1129 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
1130 }
1131
1132 struct SyncContext : public ContextBase {
1133 std::vector<std::string> deviceIdList;
1134 uint32_t mode = 0;
1135 uint32_t allowedDelayMs = 0;
1136 JsQuery* query = nullptr;
1137 napi_valuetype type = napi_undefined;
1138
GetInputOHOS::DistributedKVStore::SyncContext1139 void GetInput(napi_env env, napi_callback_info info)
1140 {
1141 auto input = [env, this](size_t argc, napi_value* argv) {
1142 // required 3 arguments :: <deviceIdList> <mode> [allowedDelayMs]
1143 ASSERT_BUSINESS_ERR(this, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
1144 this->status = JSUtil::GetValue(env, argv[0], this->deviceIdList);
1145 ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1146 "The deviceIdList parameters is incorrect.");
1147 napi_typeof(env, argv[1], &this->type);
1148 if (this->type == napi_object) {
1149 this->status = JSUtil::Unwrap(env,
1150 argv[1], reinterpret_cast<void**>(&this->query), JsQuery::Constructor(env));
1151 ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1152 "The parameters query is incorrect.");
1153 this->status = JSUtil::GetValue(env, argv[2], this->mode);
1154 ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1155 "The parameters mode is incorrect.");
1156 if (argc == 4) {
1157 this->status = JSUtil::GetValue(env, argv[3], this->allowedDelayMs);
1158 ASSERT_BUSINESS_ERR(this, (this->status == napi_ok || JSUtil::IsNull(env, argv[3])),
1159 Status::INVALID_ARGUMENT, "The parameters delay is incorrect.");
1160 this->status = napi_ok;
1161 }
1162 }
1163 if (this->type == napi_number) {
1164 this->status = JSUtil::GetValue(env, argv[1], this->mode);
1165 ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1166 "The parameters mode is incorrect.");
1167 if (argc == 3) {
1168 this->status = JSUtil::GetValue(env, argv[2], this->allowedDelayMs);
1169 ASSERT_BUSINESS_ERR(this, (this->status == napi_ok || JSUtil::IsNull(env, argv[2])),
1170 Status::INVALID_ARGUMENT, "The parameters delay is incorrect.");
1171 this->status = napi_ok;
1172 }
1173 }
1174 ASSERT_BUSINESS_ERR(this, (this->mode <= uint32_t(SyncMode::PUSH_PULL)) && (this->status == napi_ok),
1175 Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
1176 };
1177 ContextBase::GetCbInfoSync(env, info, input);
1178 }
1179 };
1180 /*
1181 * [JS API Prototype]
1182 * sync(deviceIdList:string[], mode:SyncMode, allowedDelayMs?:number):void
1183 */
Sync(napi_env env,napi_callback_info info)1184 napi_value JsSingleKVStore::Sync(napi_env env, napi_callback_info info)
1185 {
1186 auto ctxt = std::make_shared<SyncContext>();
1187 ctxt->GetInput(env, info);
1188 ASSERT_NULL(!ctxt->isThrowError, "Sync exit");
1189
1190 ZLOGD("sync deviceIdList.size=%{public}d, mode:%{public}u, allowedDelayMs:%{public}u",
1191 (int)ctxt->deviceIdList.size(), ctxt->mode, ctxt->allowedDelayMs);
1192
1193 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1194 Status status = Status::INVALID_ARGUMENT;
1195 if (ctxt->type == napi_object) {
1196 auto query = ctxt->query->GetDataQuery();
1197 status = kvStore->Sync(ctxt->deviceIdList, static_cast<SyncMode>(ctxt->mode), query, nullptr);
1198 }
1199 if (ctxt->type == napi_number) {
1200 status = kvStore->Sync(ctxt->deviceIdList, static_cast<SyncMode>(ctxt->mode), ctxt->allowedDelayMs);
1201 }
1202 ZLOGD("kvStore->Sync return %{public}d!", status);
1203 ThrowNapiError(env, status, "", false);
1204 return nullptr;
1205 }
1206
1207 /*
1208 * [JS API Prototype]
1209 * setSyncParam(defaultAllowedDelayMs:number, callback: AsyncCallback<number>):void
1210 * setSyncParam(defaultAllowedDelayMs:number):Promise<void>
1211 */
SetSyncParam(napi_env env,napi_callback_info info)1212 napi_value JsSingleKVStore::SetSyncParam(napi_env env, napi_callback_info info)
1213 {
1214 struct SyncParamContext : public ContextBase {
1215 uint32_t allowedDelayMs;
1216 };
1217 auto ctxt = std::make_shared<SyncParamContext>();
1218 auto input = [env, ctxt](size_t argc, napi_value* argv) {
1219 // required 1 arguments :: <allowedDelayMs>
1220 ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
1221 ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->allowedDelayMs);
1222 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
1223 "The parameters allowedDelayMs is incorrect.");
1224 };
1225 ctxt->GetCbInfo(env, info, input);
1226 ASSERT_NULL(!ctxt->isThrowError, "SetSyncParam exit");
1227
1228 auto execute = [ctxt]() {
1229 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1230 KvSyncParam syncParam { ctxt->allowedDelayMs };
1231 Status status = kvStore->SetSyncParam(syncParam);
1232 ZLOGD("kvStore->SetSyncParam return %{public}d", status);
1233 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1234 napi_ok : napi_generic_failure;
1235 };
1236 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
1237 }
1238
1239 /*
1240 * [JS API Prototype]
1241 * getSecurityLevel(callback: AsyncCallback<SecurityLevel>):void
1242 * getSecurityLevel():Promise<SecurityLevel>
1243 */
GetSecurityLevel(napi_env env,napi_callback_info info)1244 napi_value JsSingleKVStore::GetSecurityLevel(napi_env env, napi_callback_info info)
1245 {
1246 struct SecurityLevelContext : public ContextBase {
1247 SecurityLevel securityLevel;
1248 };
1249 auto ctxt = std::make_shared<SecurityLevelContext>();
1250 ctxt->GetCbInfo(env, info);
1251
1252 auto execute = [ctxt]() {
1253 auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1254 Status status = kvStore->GetSecurityLevel(ctxt->securityLevel);
1255 ZLOGD("kvStore->GetSecurityLevel return %{public}d", status);
1256 ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1257 napi_ok : napi_generic_failure;
1258 };
1259 auto output = [env, ctxt](napi_value& result) {
1260 ctxt->status = JSUtil::SetValue(env, static_cast<uint8_t>(ctxt->securityLevel), result);
1261 ASSERT_STATUS(ctxt, "output failed!");
1262 };
1263 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
1264 }
1265
New(napi_env env,napi_callback_info info)1266 napi_value JsSingleKVStore::New(napi_env env, napi_callback_info info)
1267 {
1268 ZLOGD("Constructor single kv store!");
1269 std::string storeId;
1270 auto ctxt = std::make_shared<ContextBase>();
1271 auto input = [env, ctxt, &storeId](size_t argc, napi_value* argv) {
1272 // required 2 arguments :: <storeId> <options>
1273 ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
1274 ctxt->status = JSUtil::GetValue(env, argv[0], storeId);
1275 ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && !storeId.empty(), Status::INVALID_ARGUMENT,
1276 "The type of storeId must be string.");
1277 };
1278 ctxt->GetCbInfoSync(env, info, input);
1279 ASSERT_NULL(!ctxt->isThrowError, "SingleKVStore new exit");
1280 ASSERT_ERR(env, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "no memory for kvStore");
1281
1282 JsSingleKVStore* kvStore = new (std::nothrow) JsSingleKVStore(storeId);
1283 ASSERT_ERR(env, kvStore != nullptr, Status::INVALID_ARGUMENT, "no memory for kvStore");
1284
1285 auto finalize = [](napi_env env, void* data, void* hint) {
1286 ZLOGI("singleKVStore finalize.");
1287 auto* kvStore = reinterpret_cast<JsSingleKVStore*>(data);
1288 ASSERT_VOID(kvStore != nullptr, "kvStore is null!");
1289 delete kvStore;
1290 };
1291 ASSERT_CALL(env, napi_wrap(env, ctxt->self, kvStore, finalize, nullptr, nullptr), kvStore);
1292 return ctxt->self;
1293 }
1294 } // namespace OHOS::DistributedKVStore
1295