• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "napi_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