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_preference.h"
17
18 #include <cerrno>
19 #include <cmath>
20 #include <limits>
21 #include <linux/limits.h>
22 #include "securec.h"
23 #include "common.h"
24
25 #include "preferences.h"
26 #include "preferences_errno.h"
27 #include "preferences_value.h"
28 #include "napi_async_proxy.h"
29
30 using namespace OHOS::NativePreferences;
31 using namespace OHOS::JsKit;
32
33 namespace OHOS {
34 namespace PreferencesJsKit {
35 #define MAX_KEY_LENGTH Preferences::MAX_KEY_LENGTH
36 #define MAX_VALUE_LENGTH Preferences::MAX_VALUE_LENGTH
37
38 struct StorageAysncContext : NapiAsyncProxy<StorageAysncContext>::AysncContext {
39 std::string key;
40 PreferencesValue defValue = PreferencesValue((int)0);
41 bool hasKey;
42 };
43
44 napi_ref PreferencesProxy::constructor;
45
PreferencesProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> value)46 PreferencesProxy::PreferencesProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> value)
47 : value_(value), env_(nullptr), wrapper_(nullptr)
48 {}
49
~PreferencesProxy()50 PreferencesProxy::~PreferencesProxy()
51 {
52 napi_delete_reference(env_, wrapper_);
53 }
54
Destructor(napi_env env,void * nativeObject,void * finalize_hint)55 void PreferencesProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
56 {
57 LOG_DEBUG("Destructor");
58 PreferencesProxy *obj = static_cast<PreferencesProxy *>(nativeObject);
59 delete obj;
60 }
61
Init(napi_env env,napi_value exports)62 void PreferencesProxy::Init(napi_env env, napi_value exports)
63 {
64 napi_property_descriptor descriptors[] = {
65 DECLARE_NAPI_FUNCTION("putSync", SetValueSync), DECLARE_NAPI_FUNCTION("put", SetValue),
66 DECLARE_NAPI_FUNCTION("getSync", GetValueSync), DECLARE_NAPI_FUNCTION("get", GetValue),
67 DECLARE_NAPI_FUNCTION("deleteSync", DeleteSync), DECLARE_NAPI_FUNCTION("delete", Delete),
68 DECLARE_NAPI_FUNCTION("clearSync", ClearSync), DECLARE_NAPI_FUNCTION("clear", Clear),
69 DECLARE_NAPI_FUNCTION("hasSync", HasKeySync), DECLARE_NAPI_FUNCTION("has", HasKey),
70 DECLARE_NAPI_FUNCTION("flushSync", FlushSync), DECLARE_NAPI_FUNCTION("flush", Flush),
71 DECLARE_NAPI_FUNCTION("on", RegisterObserver), DECLARE_NAPI_FUNCTION("off", UnRegisterObserver),
72 };
73 LOG_DEBUG("Init");
74 napi_value cons = nullptr;
75 napi_define_class(env, "Storage", NAPI_AUTO_LENGTH, New, nullptr,
76 sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons);
77
78 napi_create_reference(env, cons, 1, &constructor);
79 LOG_DEBUG("Init end");
80 }
81
NewInstance(napi_env env,napi_value arg,napi_value * instance)82 napi_status PreferencesProxy::NewInstance(napi_env env, napi_value arg, napi_value *instance)
83 {
84 napi_status status;
85
86 const int argc = 1;
87 napi_value argv[argc] = {arg};
88
89 napi_value cons;
90 status = napi_get_reference_value(env, constructor, &cons);
91 if (status != napi_ok) {
92 return status;
93 }
94
95 status = napi_new_instance(env, cons, argc, argv, instance);
96 if (status != napi_ok) {
97 return status;
98 }
99
100 return napi_ok;
101 }
102
New(napi_env env,napi_callback_info info)103 napi_value PreferencesProxy::New(napi_env env, napi_callback_info info)
104 {
105 LOG_DEBUG("New");
106 size_t argc = 1;
107 napi_value args[1] = {0};
108 napi_value _this = nullptr;
109 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
110 if (_this == nullptr) {
111 LOG_WARN("get this failed");
112 return nullptr;
113 }
114
115 napi_valuetype valueType = napi_undefined;
116 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
117 NAPI_ASSERT(env, valueType == napi_string, "input type not string");
118 char *path = new char[PATH_MAX];
119 memset_s(path, PATH_MAX, 0, PATH_MAX);
120 size_t pathLen = 0;
121 napi_status status = napi_get_value_string_utf8(env, args[0], path, PATH_MAX, &pathLen);
122 if (status != napi_ok) {
123 LOG_ERROR("get path failed. ");
124 delete[] path;
125 return nullptr;
126 }
127 // get native object
128 int errCode = 0;
129 std::shared_ptr<OHOS::NativePreferences::Preferences> preference =
130 OHOS::NativePreferences::PreferencesHelper::GetPreferences(path, errCode);
131 delete[] path;
132 NAPI_ASSERT(env, preference != nullptr, "failed to call native");
133 PreferencesProxy *obj = new PreferencesProxy(preference);
134 obj->env_ = env;
135 NAPI_CALL(env, napi_wrap(env, _this, obj, PreferencesProxy::Destructor,
136 nullptr, // finalize_hint
137 &obj->wrapper_));
138 LOG_DEBUG("New end");
139 return _this;
140 }
141
142 template<typename T>
CheckNumberType(double input)143 bool CheckNumberType(double input)
144 {
145 if (input > (std::numeric_limits<T>::max)() || input < (std::numeric_limits<T>::min)()) {
146 return false;
147 }
148 return true;
149 }
150
IsFloat(double input)151 bool IsFloat(double input)
152 {
153 return abs(input - floor(input)) >= 0; // DBL_EPSILON;
154 }
155
GetValueSync(napi_env env,napi_callback_info info)156 napi_value PreferencesProxy::GetValueSync(napi_env env, napi_callback_info info)
157 {
158 napi_value _this = nullptr;
159 size_t argc = 2; // arg count
160 napi_value args[2] = {0};
161
162 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
163 NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
164 // get value type
165 napi_valuetype valueType = napi_undefined;
166 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
167 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
168
169 // get input key
170 char key[MAX_KEY_LENGTH] = {0};
171 size_t keySize = 0;
172 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &keySize));
173 PreferencesProxy *obj = nullptr;
174 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
175 NAPI_ASSERT(env, (obj != nullptr && obj->value_ != nullptr), "unwrap null native pointer");
176
177 napi_value output = nullptr;
178 NAPI_CALL(env, napi_typeof(env, args[1], &valueType));
179 if (valueType == napi_number) {
180 double value = 0.0;
181 NAPI_CALL(env, napi_get_value_double(env, args[1], &value));
182 LOG_DEBUG("get number");
183 double result = obj->value_->GetDouble(key, value);
184 NAPI_CALL(env, napi_create_double(env, result, &output)); // double
185 LOG_DEBUG("get number end");
186 } else if (valueType == napi_string) {
187 LOG_DEBUG("get string");
188 char *value = new char[MAX_VALUE_LENGTH];
189 size_t valueSize = 0;
190 napi_get_value_string_utf8(env, args[1], value, MAX_VALUE_LENGTH, &valueSize);
191 // get value
192 std::string result = obj->value_->GetString(key, value);
193 delete[] value;
194 NAPI_CALL(env, napi_create_string_utf8(env, result.c_str(), result.size(), &output));
195 LOG_DEBUG("get string end");
196 } else if (valueType == napi_boolean) {
197 LOG_DEBUG("get bool");
198 bool value = false;
199 NAPI_CALL(env, napi_get_value_bool(env, args[1], &value));
200 // get value
201 bool result = obj->value_->GetBool(key, value);
202 NAPI_CALL(env, napi_get_boolean(env, result, &output));
203 LOG_DEBUG("get bool end");
204 } else {
205 NAPI_ASSERT(env, false, "Wrong second parameter type");
206 }
207 return output;
208 }
209
ParseKey(const napi_env & env,const napi_value & arg,StorageAysncContext * asyncContext)210 void ParseKey(const napi_env& env, const napi_value& arg, StorageAysncContext* asyncContext)
211 {
212 // get input key
213 char key[MAX_KEY_LENGTH] = { 0 };
214 size_t keySize = 0;
215 napi_get_value_string_utf8(env, arg, key, MAX_KEY_LENGTH, &keySize);
216 asyncContext->key = key;
217 }
218
ParseDefValue(const napi_env & env,const napi_value & arg,StorageAysncContext * asyncContext)219 void ParseDefValue(const napi_env& env, const napi_value& arg, StorageAysncContext* asyncContext)
220 {
221 napi_valuetype valueType = napi_undefined;
222 napi_typeof(env, arg, &valueType);
223 if (valueType == napi_number) {
224 double number = 0.0;
225 napi_get_value_double(env, arg, &number);
226 PreferencesValue value((double)number);
227 asyncContext->defValue = value;
228 } else if (valueType == napi_string) {
229 char* str = new char[MAX_VALUE_LENGTH];
230 size_t valueSize = 0;
231 napi_get_value_string_utf8(env, arg, str, MAX_VALUE_LENGTH, &valueSize);
232 PreferencesValue value((std::string)(str));
233 asyncContext->defValue = value;
234 delete[] str;
235 } else if (valueType == napi_boolean) {
236 bool bValue = false;
237 napi_get_value_bool(env, arg, &bValue);
238 PreferencesValue value((bool)(bValue));
239 asyncContext->defValue = value;
240 } else {
241 LOG_ERROR("Wrong second parameter type");
242 }
243 }
244
GetValue(napi_env env,napi_callback_info info)245 napi_value PreferencesProxy::GetValue(napi_env env, napi_callback_info info)
246 {
247 NapiAsyncProxy<StorageAysncContext> proxy;
248 proxy.Init(env, info);
249 std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
250 parsers.push_back(ParseKey);
251 parsers.push_back(ParseDefValue);
252 proxy.ParseInputs(parsers);
253
254 return proxy.DoAsyncWork(
255 "GetValue",
256 [](StorageAysncContext* asyncContext) {
257 int errCode = OK;
258 PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
259 if (asyncContext->defValue.IsBool()) {
260 bool tmpValue = (bool)obj->value_->GetBool(asyncContext->key, (bool)asyncContext->defValue);
261 asyncContext->defValue = PreferencesValue((bool)tmpValue);
262 } else if (asyncContext->defValue.IsString()) {
263 std::string tmpValue = obj->value_->GetString(asyncContext->key, (std::string)asyncContext->defValue);
264 asyncContext->defValue = PreferencesValue((std::string)tmpValue);
265 } else if (asyncContext->defValue.IsDouble()) {
266 double tmpValue = obj->value_->GetDouble(asyncContext->key, (double)asyncContext->defValue);
267 asyncContext->defValue = PreferencesValue((double)tmpValue);
268 } else {
269 errCode = ERR;
270 }
271
272 return errCode;
273 },
274 [](StorageAysncContext* asyncContext, napi_value& output) {
275 int errCode = OK;
276 if (asyncContext->defValue.IsBool()) {
277 napi_get_boolean(asyncContext->env, (bool)asyncContext->defValue, &output);
278 } else if (asyncContext->defValue.IsString()) {
279 std::string tempStr = (std::string)asyncContext->defValue;
280 napi_create_string_utf8(asyncContext->env, tempStr.c_str(), tempStr.size(), &output);
281 } else if (asyncContext->defValue.IsDouble()) {
282 napi_create_double(asyncContext->env, (double)asyncContext->defValue, &output);
283 } else {
284 errCode = ERR;
285 }
286
287 return errCode;
288 });
289 }
290
SetValueSync(napi_env env,napi_callback_info info)291 napi_value PreferencesProxy::SetValueSync(napi_env env, napi_callback_info info)
292 {
293 napi_value _this = nullptr;
294 size_t argc = 2;
295 napi_value args[2] = {0};
296
297 LOG_DEBUG("SETVALUE");
298 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
299 NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
300 // get value type
301 napi_valuetype valueType = napi_undefined;
302 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
303 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
304
305 // get input key
306 char key[MAX_KEY_LENGTH] = {0};
307 size_t out = 0;
308 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
309
310 PreferencesProxy *obj = nullptr;
311 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
312 NAPI_ASSERT(env, (obj != nullptr && obj->value_ != nullptr), "unwrap null native pointer");
313
314 NAPI_CALL(env, napi_typeof(env, args[1], &valueType));
315 if (valueType == napi_number) {
316 double value = 0.0;
317 NAPI_CALL(env, napi_get_value_double(env, args[1], &value));
318 int result = obj->value_->PutDouble(key, (double) value);
319 NAPI_ASSERT(env, result == E_OK, "call PutDouble failed");
320 } else if (valueType == napi_string) {
321 char *value = new char[MAX_VALUE_LENGTH];
322 napi_get_value_string_utf8(env, args[1], value, MAX_VALUE_LENGTH, &out);
323 // get value
324 int result = obj->value_->PutString(key, value);
325 delete[] value;
326 NAPI_ASSERT(env, result == E_OK, "call PutString failed");
327 } else if (valueType == napi_boolean) {
328 bool value = false;
329 NAPI_CALL(env, napi_get_value_bool(env, args[1], &value));
330 // get value
331 int result = obj->value_->PutBool(key, value);
332 NAPI_ASSERT(env, result == E_OK, "call PutBool failed");
333 } else {
334 NAPI_ASSERT(env, false, "Wrong second parameter type");
335 }
336 return nullptr;
337 }
338
SetValue(napi_env env,napi_callback_info info)339 napi_value PreferencesProxy::SetValue(napi_env env, napi_callback_info info)
340 {
341 NapiAsyncProxy<StorageAysncContext> proxy;
342 proxy.Init(env, info);
343 std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
344 parsers.push_back(ParseKey);
345 parsers.push_back(ParseDefValue);
346 proxy.ParseInputs(parsers);
347
348 return proxy.DoAsyncWork(
349 "SetValue",
350 [](StorageAysncContext* asyncContext) {
351 int errCode = OK;
352 PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
353 if (asyncContext->defValue.IsBool()) {
354 errCode = obj->value_->PutBool(asyncContext->key, (bool)asyncContext->defValue);
355 } else if (asyncContext->defValue.IsString()) {
356 errCode = obj->value_->PutString(asyncContext->key, (std::string)asyncContext->defValue);
357 } else if (asyncContext->defValue.IsDouble()) {
358 errCode = obj->value_->PutDouble(asyncContext->key, (double)asyncContext->defValue);
359 } else {
360 errCode = ERR;
361 }
362
363 return errCode;
364 },
365 [](StorageAysncContext* asyncContext, napi_value& output) {
366 napi_status status = napi_get_undefined(asyncContext->env, &output);
367 return (status == napi_ok) ? OK : ERR;
368 });
369 }
370
DeleteSync(napi_env env,napi_callback_info info)371 napi_value PreferencesProxy::DeleteSync(napi_env env, napi_callback_info info)
372 {
373 napi_value _this = nullptr;
374 size_t argc = 1;
375 napi_value args[1] = {0};
376 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
377 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
378 // get value type
379 napi_valuetype valueType;
380 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
381 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
382
383 char key[MAX_KEY_LENGTH] = {0};
384 size_t out = 0;
385 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
386 PreferencesProxy *obj = nullptr;
387 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
388 int result = obj->value_->Delete(key);
389 NAPI_ASSERT(env, result == E_OK, "call Delete failed");
390 LOG_INFO("Delete");
391 return nullptr;
392 }
393
Delete(napi_env env,napi_callback_info info)394 napi_value PreferencesProxy::Delete(napi_env env, napi_callback_info info)
395 {
396 NapiAsyncProxy<StorageAysncContext> proxy;
397 proxy.Init(env, info);
398 std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
399 parsers.push_back(ParseKey);
400 proxy.ParseInputs(parsers);
401
402 return proxy.DoAsyncWork(
403 "Delete",
404 [](StorageAysncContext* asyncContext) {
405 PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
406 int errCode = obj->value_->Delete(asyncContext->key);
407
408 return errCode;
409 },
410 [](StorageAysncContext* asyncContext, napi_value& output) {
411 napi_status status = napi_get_undefined(asyncContext->env, &output);
412 return (status == napi_ok) ? OK : ERR;
413 });
414 }
415
HasKeySync(napi_env env,napi_callback_info info)416 napi_value PreferencesProxy::HasKeySync(napi_env env, napi_callback_info info)
417 {
418 napi_value _this = nullptr;
419 size_t argc = 1;
420 napi_value args[1] = {0};
421 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
422 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
423 // get value type
424 napi_valuetype valueType;
425 NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
426 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
427
428 char key[MAX_KEY_LENGTH] = {0};
429 size_t out = 0;
430 NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
431 PreferencesProxy *obj = nullptr;
432 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
433 bool result = obj->value_->HasKey(key);
434 napi_value output = nullptr;
435 NAPI_CALL(env, napi_get_boolean(env, result, &output));
436 LOG_DEBUG("HasKey");
437 return output;
438 }
439
HasKey(napi_env env,napi_callback_info info)440 napi_value PreferencesProxy::HasKey(napi_env env, napi_callback_info info)
441 {
442 NapiAsyncProxy<StorageAysncContext> proxy;
443 proxy.Init(env, info);
444 std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
445 parsers.push_back(ParseKey);
446 proxy.ParseInputs(parsers);
447
448 return proxy.DoAsyncWork(
449 "HasKey",
450 [](StorageAysncContext* asyncContext) {
451 PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
452 asyncContext->hasKey = obj->value_->HasKey(asyncContext->key);
453
454 return OK;
455 },
456 [](StorageAysncContext* asyncContext, napi_value& output) {
457 napi_status status = napi_get_boolean(asyncContext->env, asyncContext->hasKey, &output);
458 return (status == napi_ok) ? OK : ERR;
459 });
460 }
461
Flush(napi_env env,napi_callback_info info)462 napi_value PreferencesProxy::Flush(napi_env env, napi_callback_info info)
463 {
464 NapiAsyncProxy<StorageAysncContext> proxy;
465 proxy.Init(env, info);
466 std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
467 proxy.ParseInputs(parsers);
468
469 return proxy.DoAsyncWork(
470 "Flush",
471 [](StorageAysncContext* asyncContext) {
472 PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
473 return obj->value_->FlushSync();
474 },
475 [](StorageAysncContext* asyncContext, napi_value& output) {
476 napi_status status = napi_get_undefined(asyncContext->env, &output);
477 return (status == napi_ok) ? OK : ERR;
478 });
479 }
480
FlushSync(napi_env env,napi_callback_info info)481 napi_value PreferencesProxy::FlushSync(napi_env env, napi_callback_info info)
482 {
483 napi_value _this = nullptr;
484 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &_this, nullptr));
485 PreferencesProxy *obj = nullptr;
486 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
487 int result = obj->value_->FlushSync();
488 napi_value output = nullptr;
489 NAPI_CALL(env, napi_create_int64(env, result, &output));
490 LOG_DEBUG("FlushSync");
491 return output;
492 }
493
ClearSync(napi_env env,napi_callback_info info)494 napi_value PreferencesProxy::ClearSync(napi_env env, napi_callback_info info)
495 {
496 napi_value _this = nullptr;
497 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &_this, nullptr));
498 PreferencesProxy *obj = nullptr;
499 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
500 int result = obj->value_->Clear();
501 NAPI_ASSERT(env, result == E_OK, "call Clear failed");
502 LOG_DEBUG("Clear");
503 return nullptr;
504 }
505
Clear(napi_env env,napi_callback_info info)506 napi_value PreferencesProxy::Clear(napi_env env, napi_callback_info info)
507 {
508 NapiAsyncProxy<StorageAysncContext> proxy;
509 proxy.Init(env, info);
510 std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
511 proxy.ParseInputs(parsers);
512
513 return proxy.DoAsyncWork(
514 "Clear",
515 [](StorageAysncContext* asyncContext) {
516 PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
517 return obj->value_->Clear();
518 },
519 [](StorageAysncContext* asyncContext, napi_value& output) {
520 napi_status status = napi_get_undefined(asyncContext->env, &output);
521 return (status == napi_ok) ? OK : ERR;
522 });
523 }
524
RegisterObserver(napi_env env,napi_callback_info info)525 napi_value PreferencesProxy::RegisterObserver(napi_env env, napi_callback_info info)
526 {
527 napi_value _this = nullptr;
528 size_t argc = 2;
529 napi_value args[2] = {0};
530
531 LOG_DEBUG("RegisterObserver");
532 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
533 napi_valuetype type;
534 NAPI_CALL(env, napi_typeof(env, args[0], &type));
535 NAPI_ASSERT(env, type == napi_string, "key not string type");
536
537 NAPI_CALL(env, napi_typeof(env, args[1], &type));
538 NAPI_ASSERT(env, type == napi_function, "observer not function type");
539
540 PreferencesProxy *obj = nullptr;
541 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
542
543 // reference save
544 obj->observer_ = std::make_shared<PreferencesObserverImpl>(env, args[1]);
545 obj->value_->RegisterObserver(obj->observer_);
546 LOG_DEBUG("RegisterObserver end");
547
548 return nullptr;
549 }
550
UnRegisterObserver(napi_env env,napi_callback_info info)551 napi_value PreferencesProxy::UnRegisterObserver(napi_env env, napi_callback_info info)
552 {
553 napi_value _this = nullptr;
554 size_t argc = 2;
555 napi_value args[2] = {0};
556 LOG_DEBUG("UnRegisterObserver");
557
558 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
559 napi_valuetype type;
560 NAPI_CALL(env, napi_typeof(env, args[0], &type));
561 NAPI_ASSERT(env, type == napi_string, "key not string type");
562
563 NAPI_CALL(env, napi_typeof(env, args[1], &type));
564 NAPI_ASSERT(env, type == napi_function, "observer not function type");
565
566 PreferencesProxy *obj = nullptr;
567 NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
568 obj->value_->UnRegisterObserver(obj->observer_);
569 obj->observer_.reset();
570 obj->observer_ = nullptr;
571 LOG_DEBUG("UnRegisterObserver end");
572 return nullptr;
573 }
574
PreferencesObserverImpl(napi_env env,napi_value callback)575 PreferencesObserverImpl::PreferencesObserverImpl(napi_env env, napi_value callback) : observerRef(nullptr)
576 {
577 this->env_ = env;
578 napi_create_reference(env_, callback, 1, &observerRef);
579 }
580
~PreferencesObserverImpl()581 PreferencesObserverImpl::~PreferencesObserverImpl()
582 {
583 napi_delete_reference(env_, observerRef);
584 }
585
OnChange(Preferences & preferences,const std::string & key)586 void PreferencesObserverImpl::OnChange(Preferences &preferences, const std::string &key)
587 {
588 LOG_DEBUG("OnChange key:%{public}s", key.c_str());
589 napi_value callback = nullptr;
590 napi_value args[1] = {0};
591
592 napi_create_string_utf8(env_, key.c_str(), key.size(), &args[0]);
593 napi_get_reference_value(env_, observerRef, &callback);
594
595 napi_value global = nullptr;
596 napi_get_global(env_, &global);
597 napi_call_function(env_, global, callback, 1, args, nullptr);
598 LOG_DEBUG("OnChange key end");
599 }
600 } // namespace PreferencesJsKit
601 } // namespace OHOS
602