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