• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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