1 /*
2 * Copyright (c) 2021 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 #include "napi_storage.h"
17
18 #include <cerrno>
19 #include <cmath>
20 #include <limits>
21
22 #include "js_logger.h"
23 #include "js_utils.h"
24 #include "napi_async_call.h"
25 #include "preferences.h"
26 #include "preferences_errno.h"
27 #include "preferences_value.h"
28 #include "securec.h"
29
30 using namespace OHOS::NativePreferences;
31 using namespace OHOS::PreferencesJsKit;
32
33 namespace OHOS {
34 namespace StorageJsKit {
35 #define MAX_KEY_LENGTH Preferences::MAX_KEY_LENGTH
36 #define MAX_VALUE_LENGTH Preferences::MAX_VALUE_LENGTH
37
38 struct StorageAysncContext : public BaseContext {
39 std::string key;
40 PreferencesValue defValue = PreferencesValue(static_cast<int>(0));
41 std::map<std::string, PreferencesValue> allElements;
42 bool hasKey = false;
43 std::list<std::string> keysModified;
44 std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers;
~StorageAysncContextOHOS::StorageJsKit::StorageAysncContext45 virtual ~StorageAysncContext(){};
46 };
47
48 static __thread napi_ref constructor_;
49
StorageProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> & value)50 StorageProxy::StorageProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> &value)
51 : value_(value), env_(nullptr), wrapper_(nullptr), uvQueue_(nullptr)
52 {
53 }
54
~StorageProxy()55 StorageProxy::~StorageProxy()
56 {
57 napi_delete_reference(env_, wrapper_);
58 for (auto &observer : dataObserver_) {
59 value_->UnRegisterObserver(observer);
60 }
61 dataObserver_.clear();
62 }
63
Destructor(napi_env env,void * nativeObject,void * finalize_hint)64 void StorageProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
65 {
66 StorageProxy *obj = static_cast<StorageProxy *>(nativeObject);
67 delete obj;
68 }
69
Init(napi_env env,napi_value exports)70 void StorageProxy::Init(napi_env env, napi_value exports)
71 {
72 napi_property_descriptor descriptors[] = {
73 DECLARE_NAPI_FUNCTION("putSync", SetValueSync),
74 DECLARE_NAPI_FUNCTION("put", SetValue),
75 DECLARE_NAPI_FUNCTION("getSync", GetValueSync),
76 DECLARE_NAPI_FUNCTION("get", GetValue),
77 DECLARE_NAPI_FUNCTION("deleteSync", DeleteSync),
78 DECLARE_NAPI_FUNCTION("delete", Delete),
79 DECLARE_NAPI_FUNCTION("clearSync", ClearSync),
80 DECLARE_NAPI_FUNCTION("clear", Clear),
81 DECLARE_NAPI_FUNCTION("hasSync", HasKeySync),
82 DECLARE_NAPI_FUNCTION("has", HasKey),
83 DECLARE_NAPI_FUNCTION("flushSync", FlushSync),
84 DECLARE_NAPI_FUNCTION("flush", Flush),
85 DECLARE_NAPI_FUNCTION("on", RegisterObserver),
86 DECLARE_NAPI_FUNCTION("off", UnRegisterObserver),
87 };
88 napi_value cons = nullptr;
89 napi_define_class(env, "Storage", NAPI_AUTO_LENGTH, New, nullptr,
90 sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons);
91
92 napi_create_reference(env, cons, 1, &constructor_);
93 }
94
NewInstance(napi_env env,napi_value arg,napi_value * instance)95 napi_status StorageProxy::NewInstance(napi_env env, napi_value arg, napi_value *instance)
96 {
97 napi_status status;
98
99 const int argc = 1;
100 napi_value argv[argc] = { arg };
101
102 napi_value cons;
103 status = napi_get_reference_value(env, constructor_, &cons);
104 if (status != napi_ok) {
105 return status;
106 }
107
108 status = napi_new_instance(env, cons, argc, argv, instance);
109 if (status != napi_ok) {
110 return status;
111 }
112
113 return napi_ok;
114 }
115
New(napi_env env,napi_callback_info info)116 napi_value StorageProxy::New(napi_env env, napi_callback_info info)
117 {
118 size_t argc = 1;
119 napi_value args[1] = { 0 };
120 napi_value thiz = nullptr;
121 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
122 if (thiz == nullptr) {
123 LOG_WARN("get this failed");
124 return nullptr;
125 }
126
127 napi_valuetype valueType = napi_undefined;
128 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
129 NAPI_ASSERT(env, valueType == napi_string, "input type not string");
130 char *path = new (std::nothrow) char[PATH_MAX];
131 if (path == nullptr) {
132 LOG_ERROR("StorageProxy::New new failed, path is nullptr");
133 return nullptr;
134 }
135 size_t pathLen = 0;
136 napi_status status = napi_get_value_string_utf8(env, args[0], path, PATH_MAX, &pathLen);
137 if (status != napi_ok) {
138 LOG_ERROR("get path failed. ");
139 delete[] path;
140 return nullptr;
141 }
142 // get native object
143 int errCode = 0;
144 std::shared_ptr<OHOS::NativePreferences::Preferences> preference =
145 OHOS::NativePreferences::PreferencesHelper::GetPreferences(path, errCode);
146 delete[] path;
147 NAPI_ASSERT(env, preference != nullptr, "failed to call native");
148 StorageProxy *obj = new (std::nothrow) StorageProxy(preference);
149 if (obj == nullptr) {
150 LOG_ERROR("StorageProxy::New new failed, obj is nullptr");
151 return nullptr;
152 }
153 obj->env_ = env;
154 obj->value_ = std::move(preference);
155 obj->uvQueue_ = std::make_shared<UvQueue>(env);
156 NAPI_CALL(env, napi_wrap(env, thiz, obj, StorageProxy::Destructor,
157 nullptr, // finalize_hint
158 &obj->wrapper_));
159 return thiz;
160 }
161
CheckNumberType(double input)162 template<typename T> bool CheckNumberType(double input)
163 {
164 if (input > (std::numeric_limits<T>::max)() || input < (std::numeric_limits<T>::min)()) {
165 return false;
166 }
167 return true;
168 }
169
GetValueSync(napi_env env,napi_callback_info info)170 napi_value StorageProxy::GetValueSync(napi_env env, napi_callback_info info)
171 {
172 napi_value thiz = nullptr;
173 size_t argc = 2; // arg count
174 napi_value args[2] = { 0 };
175
176 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
177 NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
178 // get value type
179 napi_valuetype valueType = napi_undefined;
180 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
181 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
182
183 // get input key
184 char key[MAX_KEY_LENGTH] = { 0 };
185 size_t keySize = 0;
186 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &keySize));
187 StorageProxy *obj = nullptr;
188 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
189 NAPI_ASSERT(env, (obj != nullptr && obj->value_ != nullptr), "unwrap null native pointer");
190
191 napi_value output = nullptr;
192 NAPI_CALL(env, napi_typeof(env, args[1], &valueType));
193 if (valueType == napi_number) {
194 double value = 0.0;
195 NAPI_CALL(env, napi_get_value_double(env, args[1], &value));
196 double result = obj->value_->GetDouble(key, value);
197 NAPI_CALL(env, napi_create_double(env, result, &output)); // double
198 } else if (valueType == napi_string) {
199 char *value = new (std::nothrow) char[MAX_VALUE_LENGTH];
200 if (value == nullptr) {
201 LOG_ERROR("StorageProxy::GetValueSync new failed, value is nullptr");
202 return nullptr;
203 }
204 size_t valueSize = 0;
205 napi_get_value_string_utf8(env, args[1], value, MAX_VALUE_LENGTH, &valueSize);
206 // get value
207 std::string result = obj->value_->GetString(key, value);
208 delete[] value;
209 NAPI_CALL(env, napi_create_string_utf8(env, result.c_str(), result.size(), &output));
210 } else if (valueType == napi_boolean) {
211 bool value = false;
212 NAPI_CALL(env, napi_get_value_bool(env, args[1], &value));
213 // get value
214 bool result = obj->value_->GetBool(key, value);
215 NAPI_CALL(env, napi_get_boolean(env, result, &output));
216 } else {
217 NAPI_ASSERT(env, false, "Wrong second parameter type");
218 }
219 return output;
220 }
221
ParseKey(const napi_env & env,const napi_value & arg,std::shared_ptr<StorageAysncContext> asyncContext)222 int ParseKey(const napi_env &env, const napi_value &arg, std::shared_ptr<StorageAysncContext> asyncContext)
223 {
224 // get input key
225 char key[MAX_KEY_LENGTH] = { 0 };
226 size_t keySize = 0;
227 napi_get_value_string_utf8(env, arg, key, MAX_KEY_LENGTH, &keySize);
228 asyncContext->key = std::string(key);
229 return OK;
230 }
231
ParseDefValue(const napi_env & env,const napi_value & jsVal,std::shared_ptr<StorageAysncContext> asyncContext)232 int ParseDefValue(const napi_env &env, const napi_value &jsVal, std::shared_ptr<StorageAysncContext> asyncContext)
233 {
234 napi_valuetype valueType = napi_undefined;
235 napi_typeof(env, jsVal, &valueType);
236 if (valueType == napi_number) {
237 double number = 0.0;
238 if (JSUtils::Convert2Double(env, jsVal, number) != E_OK) {
239 LOG_ERROR("ParseDefValue Convert2Double error");
240 return ERR;
241 }
242 asyncContext->defValue = number;
243 } else if (valueType == napi_string) {
244 std::string str;
245 if (JSUtils::Convert2String(env, jsVal, str) != E_OK) {
246 LOG_ERROR("ParseDefValue Convert2String error");
247 return ERR;
248 }
249 asyncContext->defValue = str;
250 } else if (valueType == napi_boolean) {
251 bool bValue = false;
252 if (JSUtils::Convert2Bool(env, jsVal, bValue) != E_OK) {
253 LOG_ERROR("ParseDefValue Convert2Bool error");
254 return ERR;
255 }
256 asyncContext->defValue = bValue;
257 } else {
258 LOG_ERROR("Wrong second parameter type");
259 }
260 return OK;
261 }
262
GetValue(napi_env env,napi_callback_info info)263 napi_value StorageProxy::GetValue(napi_env env, napi_callback_info info)
264 {
265 LOG_DEBUG("GetValue start");
266 auto context = std::make_shared<StorageAysncContext>();
267 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int {
268 std::shared_ptr<Error> paramNumError = std::make_shared<ParamNumError>("2 or 3");
269 PRE_CHECK_RETURN_CALL_RESULT(argc == 2 || argc == 3, context->SetError(paramNumError));
270 PRE_ASYNC_PARAM_CHECK_FUNCTION(ParseKey(env, argv[0], context));
271 PRE_ASYNC_PARAM_CHECK_FUNCTION(ParseDefValue(env, argv[1], context));
272 napi_unwrap(env, self, &context->boundObj);
273 return OK;
274 };
275 auto exec = [context]() -> int {
276 int errCode = OK;
277 StorageProxy *obj = reinterpret_cast<StorageProxy *>(context->boundObj);
278 if (context->defValue.IsBool()) {
279 bool tmpValue = (bool)obj->value_->GetBool(context->key, context->defValue);
280 context->defValue = PreferencesValue(tmpValue);
281 } else if (context->defValue.IsString()) {
282 std::string tmpValue = obj->value_->GetString(context->key, context->defValue);
283 context->defValue = PreferencesValue(tmpValue);
284 } else if (context->defValue.IsDouble()) {
285 double tmpValue = obj->value_->GetDouble(context->key, context->defValue);
286 context->defValue = PreferencesValue(tmpValue);
287 } else {
288 errCode = ERR;
289 }
290
291 return errCode;
292 };
293 auto output = [context](napi_env env, napi_value &result) -> int {
294 int errCode = OK;
295 if (context->defValue.IsBool()) {
296 napi_get_boolean(context->env_, context->defValue, &result);
297 } else if (context->defValue.IsString()) {
298 std::string tempStr = (std::string)context->defValue;
299 napi_create_string_utf8(context->env_, tempStr.c_str(), tempStr.size(), &result);
300 } else if (context->defValue.IsDouble()) {
301 napi_create_double(context->env_, context->defValue, &result);
302 } else {
303 errCode = ERR;
304 }
305
306 return errCode;
307 };
308 context->SetAction(env, info, input, exec, output);
309
310 PRE_CHECK_RETURN_NULLPTR(context, context->error == nullptr || context->error->GetCode() == OK);
311 return AsyncCall::Call(env, context);
312 }
313
SetValueSync(napi_env env,napi_callback_info info)314 napi_value StorageProxy::SetValueSync(napi_env env, napi_callback_info info)
315 {
316 napi_value thiz = nullptr;
317 size_t argc = 2;
318 napi_value args[2] = { 0 };
319
320 LOG_DEBUG("SETVALUE");
321 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
322 NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
323 // get value type
324 napi_valuetype valueType = napi_undefined;
325 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
326 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
327
328 // get input key
329 char key[MAX_KEY_LENGTH] = { 0 };
330 size_t out = 0;
331 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
332
333 StorageProxy *obj = nullptr;
334 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
335 NAPI_ASSERT(env, (obj != nullptr && obj->value_ != nullptr), "unwrap null native pointer");
336
337 NAPI_CALL(env, napi_typeof(env, args[1], &valueType));
338 if (valueType == napi_number) {
339 double value = 0.0;
340 NAPI_CALL(env, napi_get_value_double(env, args[1], &value));
341 int result = obj->value_->PutDouble(key, value);
342 NAPI_ASSERT(env, result == E_OK, "call PutDouble failed");
343 } else if (valueType == napi_string) {
344 char *value = new char[MAX_VALUE_LENGTH];
345 napi_get_value_string_utf8(env, args[1], value, MAX_VALUE_LENGTH, &out);
346 // get value
347 int result = obj->value_->PutString(key, value);
348 delete[] value;
349 NAPI_ASSERT(env, result == E_OK, "call PutString failed");
350 } else if (valueType == napi_boolean) {
351 bool value = false;
352 NAPI_CALL(env, napi_get_value_bool(env, args[1], &value));
353 // get value
354 int result = obj->value_->PutBool(key, value);
355 NAPI_ASSERT(env, result == E_OK, "call PutBool failed");
356 } else {
357 NAPI_ASSERT(env, false, "Wrong second parameter type");
358 }
359 return nullptr;
360 }
361
SetValue(napi_env env,napi_callback_info info)362 napi_value StorageProxy::SetValue(napi_env env, napi_callback_info info)
363 {
364 LOG_DEBUG("SetValue start");
365 auto context = std::make_shared<StorageAysncContext>();
366 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int {
367 std::shared_ptr<Error> paramNumError = std::make_shared<ParamNumError>("2 or 3");
368 PRE_CHECK_RETURN_CALL_RESULT(argc == 2 || argc == 3, context->SetError(paramNumError));
369 PRE_ASYNC_PARAM_CHECK_FUNCTION(ParseKey(env, argv[0], context));
370 PRE_ASYNC_PARAM_CHECK_FUNCTION(ParseDefValue(env, argv[1], context));
371 napi_unwrap(env, self, &context->boundObj);
372 return OK;
373 };
374 auto exec = [context]() -> int {
375 int errCode = OK;
376 StorageProxy *obj = reinterpret_cast<StorageProxy *>(context->boundObj);
377 if (context->defValue.IsBool()) {
378 errCode = obj->value_->PutBool(context->key, context->defValue);
379 } else if (context->defValue.IsString()) {
380 errCode = obj->value_->PutString(context->key, context->defValue);
381 } else if (context->defValue.IsDouble()) {
382 errCode = obj->value_->PutDouble(context->key, context->defValue);
383 } else {
384 errCode = ERR;
385 }
386
387 return errCode;
388 };
389 auto output = [context](napi_env env, napi_value &result) -> int {
390 napi_status status = napi_get_undefined(context->env_, &result);
391 return (status == napi_ok) ? OK : ERR;
392 };
393 context->SetAction(env, info, input, exec, output);
394
395 PRE_CHECK_RETURN_NULLPTR(context, context->error == nullptr || context->error->GetCode() == OK);
396 return AsyncCall::Call(env, context);
397 }
398
DeleteSync(napi_env env,napi_callback_info info)399 napi_value StorageProxy::DeleteSync(napi_env env, napi_callback_info info)
400 {
401 napi_value thiz = nullptr;
402 size_t argc = 1;
403 napi_value args[1] = { 0 };
404 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
405 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
406 // get value type
407 napi_valuetype valueType;
408 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
409 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
410
411 char key[MAX_KEY_LENGTH] = { 0 };
412 size_t out = 0;
413 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
414 StorageProxy *obj = nullptr;
415 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
416 int result = obj->value_->Delete(key);
417 NAPI_ASSERT(env, result == E_OK, "call Delete failed");
418 LOG_INFO("Delete");
419 return nullptr;
420 }
421
Delete(napi_env env,napi_callback_info info)422 napi_value StorageProxy::Delete(napi_env env, napi_callback_info info)
423 {
424 LOG_DEBUG("Delete start");
425 auto context = std::make_shared<StorageAysncContext>();
426 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int {
427 std::shared_ptr<Error> paramNumError = std::make_shared<ParamNumError>("1 or 2");
428 PRE_CHECK_RETURN_CALL_RESULT(argc == 1 || argc == 2, context->SetError(paramNumError));
429 PRE_ASYNC_PARAM_CHECK_FUNCTION(ParseKey(env, argv[0], context));
430 PRE_ASYNC_PARAM_CHECK_FUNCTION(ParseDefValue(env, argv[1], context));
431 napi_unwrap(env, self, &context->boundObj);
432 return OK;
433 };
434 auto exec = [context]() -> int {
435 StorageProxy *obj = reinterpret_cast<StorageProxy *>(context->boundObj);
436 int errCode = obj->value_->Delete(context->key);
437 return errCode;
438 };
439 auto output = [context](napi_env env, napi_value &result) -> int {
440 napi_status status = napi_get_undefined(context->env_, &result);
441 return (status == napi_ok) ? OK : ERR;
442 };
443 context->SetAction(env, info, input, exec, output);
444
445 PRE_CHECK_RETURN_NULLPTR(context, context->error == nullptr || context->error->GetCode() == OK);
446 return AsyncCall::Call(env, context);
447 }
448
HasKeySync(napi_env env,napi_callback_info info)449 napi_value StorageProxy::HasKeySync(napi_env env, napi_callback_info info)
450 {
451 napi_value thiz = nullptr;
452 size_t argc = 1;
453 napi_value args[1] = { 0 };
454 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
455 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
456 // get value type
457 napi_valuetype valueType;
458 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
459 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
460
461 char key[MAX_KEY_LENGTH] = { 0 };
462 size_t out = 0;
463 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
464 StorageProxy *obj = nullptr;
465 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
466 bool result = obj->value_->HasKey(key);
467 napi_value output = nullptr;
468 NAPI_CALL(env, napi_get_boolean(env, result, &output));
469 LOG_DEBUG("HasKey");
470 return output;
471 }
472
HasKey(napi_env env,napi_callback_info info)473 napi_value StorageProxy::HasKey(napi_env env, napi_callback_info info)
474 {
475 LOG_DEBUG("HasKeySync start");
476 auto context = std::make_shared<StorageAysncContext>();
477 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int {
478 std::shared_ptr<Error> paramNumError = std::make_shared<ParamNumError>("1 or 2");
479 PRE_CHECK_RETURN_CALL_RESULT(argc == 1 || argc == 2, context->SetError(paramNumError));
480 PRE_ASYNC_PARAM_CHECK_FUNCTION(ParseKey(env, argv[0], context));
481 napi_unwrap(env, self, &context->boundObj);
482 return OK;
483 };
484 auto exec = [context]() -> int {
485 StorageProxy *obj = reinterpret_cast<StorageProxy *>(context->boundObj);
486 context->hasKey = obj->value_->HasKey(context->key);
487
488 return OK;
489 };
490 auto output = [context](napi_env env, napi_value &result) -> int {
491 napi_status status = napi_get_boolean(context->env_, context->hasKey, &result);
492 return (status == napi_ok) ? OK : ERR;
493 };
494 context->SetAction(env, info, input, exec, output);
495
496 PRE_CHECK_RETURN_NULLPTR(context, context->error == nullptr || context->error->GetCode() == OK);
497 return AsyncCall::Call(env, context);
498 }
499
Flush(napi_env env,napi_callback_info info)500 napi_value StorageProxy::Flush(napi_env env, napi_callback_info info)
501 {
502 LOG_DEBUG("Flush start");
503 auto context = std::make_shared<StorageAysncContext>();
504 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int {
505 std::shared_ptr<Error> paramNumError = std::make_shared<ParamNumError>("0 or 1");
506 PRE_CHECK_RETURN_CALL_RESULT(argc == 0 || argc == 1, context->SetError(paramNumError));
507 napi_unwrap(env, self, &context->boundObj);
508 return OK;
509 };
510 auto exec = [context]() -> int {
511 StorageProxy *obj = reinterpret_cast<StorageProxy *>(context->boundObj);
512 return obj->value_->FlushSync();
513 };
514 auto output = [context](napi_env env, napi_value &result) -> int {
515 napi_status status = napi_get_undefined(context->env_, &result);
516 return (status == napi_ok) ? OK : ERR;
517 };
518 context->SetAction(env, info, input, exec, output);
519
520 PRE_CHECK_RETURN_NULLPTR(context, context->error == nullptr || context->error->GetCode() == OK);
521 return AsyncCall::Call(env, context);
522 }
523
FlushSync(napi_env env,napi_callback_info info)524 napi_value StorageProxy::FlushSync(napi_env env, napi_callback_info info)
525 {
526 napi_value thiz = nullptr;
527 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thiz, nullptr));
528 StorageProxy *obj = nullptr;
529 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
530 int result = obj->value_->FlushSync();
531 napi_value output = nullptr;
532 NAPI_CALL(env, napi_create_int64(env, result, &output));
533 LOG_DEBUG("FlushSync");
534 return output;
535 }
536
ClearSync(napi_env env,napi_callback_info info)537 napi_value StorageProxy::ClearSync(napi_env env, napi_callback_info info)
538 {
539 napi_value thiz = nullptr;
540 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thiz, nullptr));
541 StorageProxy *obj = nullptr;
542 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
543 int result = obj->value_->Clear();
544 NAPI_ASSERT(env, result == E_OK, "call Clear failed");
545 LOG_DEBUG("Clear");
546 return nullptr;
547 }
548
Clear(napi_env env,napi_callback_info info)549 napi_value StorageProxy::Clear(napi_env env, napi_callback_info info)
550 {
551 LOG_DEBUG("Flush start");
552 auto context = std::make_shared<StorageAysncContext>();
553 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int {
554 std::shared_ptr<Error> paramNumError = std::make_shared<ParamNumError>("0 or 1");
555 PRE_CHECK_RETURN_CALL_RESULT(argc == 0 || argc == 1, context->SetError(paramNumError));
556 napi_unwrap(env, self, &context->boundObj);
557 return OK;
558 };
559 auto exec = [context]() -> int {
560 StorageProxy *obj = reinterpret_cast<StorageProxy *>(context->boundObj);
561 return obj->value_->Clear();
562 };
563 auto output = [context](napi_env env, napi_value &result) -> int {
564 napi_status status = napi_get_undefined(context->env_, &result);
565 return (status == napi_ok) ? OK : ERR;
566 };
567 context->SetAction(env, info, input, exec, output);
568
569 PRE_CHECK_RETURN_NULLPTR(context, context->error == nullptr || context->error->GetCode() == OK);
570 return AsyncCall::Call(env, context);
571 }
572
RegisterObserver(napi_env env,napi_callback_info info)573 napi_value StorageProxy::RegisterObserver(napi_env env, napi_callback_info info)
574 {
575 napi_value thiz = nullptr;
576 size_t argc = 2;
577 napi_value args[2] = { 0 };
578
579 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
580 napi_valuetype type;
581 NAPI_CALL(env, napi_typeof(env, args[0], &type));
582 NAPI_ASSERT(env, type == napi_string, "type should be 'change'");
583
584 std::string change;
585 int ret = JSUtils::Convert2String(env, args[0], change);
586 NAPI_ASSERT(env, ret == OK && change == "change", "type should be 'change'");
587
588 NAPI_CALL(env, napi_typeof(env, args[1], &type));
589 NAPI_ASSERT(env, type == napi_function, "observer not function type");
590
591 StorageProxy *obj = nullptr;
592 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
593 obj->RegisterObserver(args[1]);
594
595 return nullptr;
596 }
597
UnRegisterObserver(napi_env env,napi_callback_info info)598 napi_value StorageProxy::UnRegisterObserver(napi_env env, napi_callback_info info)
599 {
600 napi_value thiz = nullptr;
601 size_t argc = 2;
602 napi_value args[2] = { 0 };
603
604 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
605 napi_valuetype type;
606 NAPI_CALL(env, napi_typeof(env, args[0], &type));
607 NAPI_ASSERT(env, type == napi_string, "key not string type");
608
609 std::string change;
610 int ret = JSUtils::Convert2String(env, args[0], change);
611 NAPI_ASSERT(env, ret == OK && change == "change", "type should be 'change'");
612
613 NAPI_CALL(env, napi_typeof(env, args[1], &type));
614 NAPI_ASSERT(env, type == napi_function, "observer not function type");
615
616 StorageProxy *obj = nullptr;
617 NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
618 obj->UnRegisterObserver(args[1]);
619
620 return nullptr;
621 }
622
HasRegisteredObserver(napi_value callback)623 bool StorageProxy::HasRegisteredObserver(napi_value callback)
624 {
625 std::lock_guard<std::mutex> lck(listMutex_);
626 for (auto &it : dataObserver_) {
627 if (JSUtils::Equals(env_, callback, it->GetCallback())) {
628 LOG_INFO("The observer has already subscribed.");
629 return true;
630 }
631 }
632 return false;
633 }
634
RegisterObserver(napi_value callback)635 void StorageProxy::RegisterObserver(napi_value callback)
636 {
637 if (!HasRegisteredObserver(callback)) {
638 auto observer = std::make_shared<JSPreferencesObserver>(uvQueue_, callback);
639 value_->RegisterObserver(observer);
640 dataObserver_.push_back(observer);
641 LOG_INFO("The observer subscribed success.");
642 }
643 }
644
UnRegisterObserver(napi_value callback)645 void StorageProxy::UnRegisterObserver(napi_value callback)
646 {
647 std::lock_guard<std::mutex> lck(listMutex_);
648 auto it = dataObserver_.begin();
649 while (it != dataObserver_.end()) {
650 if (!JSUtils::Equals(env_, callback, (*it)->GetCallback())) {
651 ++it;
652 continue; // specified observer and not current iterator
653 }
654 value_->UnRegisterObserver(*it);
655 it = dataObserver_.erase(it);
656 LOG_INFO("The observer unsubscribed success.");
657 }
658 }
659 } // namespace StorageJsKit
660 } // namespace OHOS
661