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