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