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