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