• 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_preferences.h"
17 
18 #include <linux/limits.h>
19 
20 #include <cerrno>
21 #include <cmath>
22 #include <limits>
23 
24 #include "js_logger.h"
25 #include "napi_async_proxy.h"
26 #include "preferences.h"
27 #include "preferences_errno.h"
28 #include "preferences_value.h"
29 #include "securec.h"
30 
31 using namespace OHOS::NativePreferences;
32 using namespace OHOS::AppDataMgrJsKit;
33 
34 namespace OHOS {
35 namespace PreferencesJsKit {
36 #define MAX_KEY_LENGTH Preferences::MAX_KEY_LENGTH
37 #define MAX_VALUE_LENGTH Preferences::MAX_VALUE_LENGTH
38 
39 struct PreferencesAysncContext : NapiAsyncProxy<PreferencesAysncContext>::AysncContext {
40     std::string key;
41     PreferencesValue defValue = PreferencesValue((int)0);
42     bool hasKey;
43 };
44 
45 static __thread napi_ref constructor_;
46 
PreferencesProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> & value)47 PreferencesProxy::PreferencesProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> &value)
48     : value_(value), env_(nullptr), wrapper_(nullptr)
49 {
50 }
51 
~PreferencesProxy()52 PreferencesProxy::~PreferencesProxy()
53 {
54     napi_delete_reference(env_, wrapper_);
55 }
56 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)57 void PreferencesProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
58 {
59     PreferencesProxy *obj = static_cast<PreferencesProxy *>(nativeObject);
60     delete obj;
61 }
62 
Init(napi_env env,napi_value exports)63 void PreferencesProxy::Init(napi_env env, napi_value exports)
64 {
65     napi_property_descriptor descriptors[] = {
66         DECLARE_NAPI_FUNCTION("put", SetValue),
67         DECLARE_NAPI_FUNCTION("get", GetValue),
68         DECLARE_NAPI_FUNCTION("delete", Delete),
69         DECLARE_NAPI_FUNCTION("clear", Clear),
70         DECLARE_NAPI_FUNCTION("has", HasKey),
71         DECLARE_NAPI_FUNCTION("flush", Flush),
72         DECLARE_NAPI_FUNCTION("on", RegisterObserver),
73         DECLARE_NAPI_FUNCTION("off", UnRegisterObserver),
74     };
75     napi_value cons = nullptr;
76     napi_define_class(env, "Storage", NAPI_AUTO_LENGTH, New, nullptr,
77         sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons);
78 
79     napi_create_reference(env, cons, 1, &constructor_);
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     size_t argc = 1;
106     napi_value args[1] = { 0 };
107     napi_value thiz = nullptr;
108     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
109     if (thiz == nullptr) {
110         LOG_WARN("get this failed");
111         return nullptr;
112     }
113 
114     napi_valuetype valueType = napi_undefined;
115     NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
116     NAPI_ASSERT(env, valueType == napi_string, "input type not string");
117     char *path = new char[PATH_MAX];
118     size_t pathLen = 0;
119     napi_status status = napi_get_value_string_utf8(env, args[0], path, PATH_MAX, &pathLen);
120     if (status != napi_ok) {
121         LOG_ERROR("get path failed. ");
122         delete[] path;
123         return nullptr;
124     }
125     // get native object
126     int errCode = 0;
127     std::shared_ptr<OHOS::NativePreferences::Preferences> preference =
128         OHOS::NativePreferences::PreferencesHelper::GetPreferences(path, errCode);
129     delete[] path;
130     NAPI_ASSERT(env, preference != nullptr, "failed to call native");
131     PreferencesProxy *obj = new PreferencesProxy(preference);
132     obj->env_ = env;
133     NAPI_CALL(env, napi_wrap(env, thiz, obj, PreferencesProxy::Destructor,
134                        nullptr, // finalize_hint
135                        &obj->wrapper_));
136     return thiz;
137 }
138 
CheckNumberType(double input)139 template<typename T> bool CheckNumberType(double input)
140 {
141     if (input > (std::numeric_limits<T>::max)() || input < (std::numeric_limits<T>::min)()) {
142         return false;
143     }
144     return true;
145 }
146 
IsFloat(double input)147 bool IsFloat(double input)
148 {
149     return abs(input - floor(input)) >= 0; // DBL_EPSILON;
150 }
151 
ParseKey(const napi_env & env,const napi_value & arg,PreferencesAysncContext * asyncContext)152 void ParseKey(const napi_env &env, const napi_value &arg, PreferencesAysncContext *asyncContext)
153 {
154     // get input key
155     char key[MAX_KEY_LENGTH] = { 0 };
156     size_t keySize = 0;
157     napi_get_value_string_utf8(env, arg, key, MAX_KEY_LENGTH, &keySize);
158     asyncContext->key = key;
159 }
160 
ParseDefValue(const napi_env & env,const napi_value & arg,PreferencesAysncContext * asyncContext)161 void ParseDefValue(const napi_env &env, const napi_value &arg, PreferencesAysncContext *asyncContext)
162 {
163     napi_valuetype valueType = napi_undefined;
164     napi_typeof(env, arg, &valueType);
165     if (valueType == napi_number) {
166         double number = 0.0;
167         napi_get_value_double(env, arg, &number);
168         PreferencesValue value((double)number);
169         asyncContext->defValue = value;
170     } else if (valueType == napi_string) {
171         char *str = new char[MAX_VALUE_LENGTH];
172         size_t valueSize = 0;
173         napi_get_value_string_utf8(env, arg, str, MAX_VALUE_LENGTH, &valueSize);
174         PreferencesValue value((std::string)(str));
175         asyncContext->defValue = value;
176         delete[] str;
177     } else if (valueType == napi_boolean) {
178         bool bValue = false;
179         napi_get_value_bool(env, arg, &bValue);
180         PreferencesValue value((bool)(bValue));
181         asyncContext->defValue = value;
182     } else {
183         LOG_ERROR("Wrong second parameter type");
184     }
185 }
186 
GetValue(napi_env env,napi_callback_info info)187 napi_value PreferencesProxy::GetValue(napi_env env, napi_callback_info info)
188 {
189     NapiAsyncProxy<PreferencesAysncContext> proxy;
190     proxy.Init(env, info);
191     std::vector<NapiAsyncProxy<PreferencesAysncContext>::InputParser> parsers;
192     parsers.push_back(ParseKey);
193     parsers.push_back(ParseDefValue);
194     proxy.ParseInputs(parsers);
195 
196     return proxy.DoAsyncWork(
197         "GetValue",
198         [](PreferencesAysncContext *asyncContext) {
199             int errCode = OK;
200             PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(asyncContext->boundObj);
201             if (asyncContext->defValue.IsBool()) {
202                 bool tmpValue = (bool)obj->value_->GetBool(asyncContext->key, (bool)asyncContext->defValue);
203                 asyncContext->defValue = PreferencesValue((bool)tmpValue);
204             } else if (asyncContext->defValue.IsString()) {
205                 std::string tmpValue = obj->value_->GetString(asyncContext->key, (std::string)asyncContext->defValue);
206                 asyncContext->defValue = PreferencesValue((std::string)tmpValue);
207             } else if (asyncContext->defValue.IsDouble()) {
208                 double tmpValue = obj->value_->GetDouble(asyncContext->key, (double)asyncContext->defValue);
209                 asyncContext->defValue = PreferencesValue((double)tmpValue);
210             } else {
211                 errCode = ERR;
212             }
213 
214             return errCode;
215         },
216         [](PreferencesAysncContext *asyncContext, napi_value &output) {
217             int errCode = OK;
218             if (asyncContext->defValue.IsBool()) {
219                 napi_get_boolean(asyncContext->env, (bool)asyncContext->defValue, &output);
220             } else if (asyncContext->defValue.IsString()) {
221                 std::string tempStr = (std::string)asyncContext->defValue;
222                 napi_create_string_utf8(asyncContext->env, tempStr.c_str(), tempStr.size(), &output);
223             } else if (asyncContext->defValue.IsDouble()) {
224                 napi_create_double(asyncContext->env, (double)asyncContext->defValue, &output);
225             } else {
226                 errCode = ERR;
227             }
228 
229             return errCode;
230         });
231 }
232 
SetValue(napi_env env,napi_callback_info info)233 napi_value PreferencesProxy::SetValue(napi_env env, napi_callback_info info)
234 {
235     NapiAsyncProxy<PreferencesAysncContext> proxy;
236     proxy.Init(env, info);
237     std::vector<NapiAsyncProxy<PreferencesAysncContext>::InputParser> parsers;
238     parsers.push_back(ParseKey);
239     parsers.push_back(ParseDefValue);
240     proxy.ParseInputs(parsers);
241 
242     return proxy.DoAsyncWork(
243         "SetValue",
244         [](PreferencesAysncContext *asyncContext) {
245             int errCode = OK;
246             PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(asyncContext->boundObj);
247             if (asyncContext->defValue.IsBool()) {
248                 errCode = obj->value_->PutBool(asyncContext->key, (bool)asyncContext->defValue);
249             } else if (asyncContext->defValue.IsString()) {
250                 errCode = obj->value_->PutString(asyncContext->key, (std::string)asyncContext->defValue);
251             } else if (asyncContext->defValue.IsDouble()) {
252                 errCode = obj->value_->PutDouble(asyncContext->key, (double)asyncContext->defValue);
253             } else {
254                 errCode = ERR;
255             }
256 
257             return errCode;
258         },
259         [](PreferencesAysncContext *asyncContext, napi_value &output) {
260             napi_status status = napi_get_undefined(asyncContext->env, &output);
261             return (status == napi_ok) ? OK : ERR;
262         });
263 }
264 
Delete(napi_env env,napi_callback_info info)265 napi_value PreferencesProxy::Delete(napi_env env, napi_callback_info info)
266 {
267     NapiAsyncProxy<PreferencesAysncContext> proxy;
268     proxy.Init(env, info);
269     std::vector<NapiAsyncProxy<PreferencesAysncContext>::InputParser> parsers;
270     parsers.push_back(ParseKey);
271     proxy.ParseInputs(parsers);
272 
273     return proxy.DoAsyncWork(
274         "Delete",
275         [](PreferencesAysncContext *asyncContext) {
276             PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(asyncContext->boundObj);
277             int errCode = obj->value_->Delete(asyncContext->key);
278 
279             return errCode;
280         },
281         [](PreferencesAysncContext *asyncContext, napi_value &output) {
282             napi_status status = napi_get_undefined(asyncContext->env, &output);
283             return (status == napi_ok) ? OK : ERR;
284         });
285 }
286 
HasKey(napi_env env,napi_callback_info info)287 napi_value PreferencesProxy::HasKey(napi_env env, napi_callback_info info)
288 {
289     NapiAsyncProxy<PreferencesAysncContext> proxy;
290     proxy.Init(env, info);
291     std::vector<NapiAsyncProxy<PreferencesAysncContext>::InputParser> parsers;
292     parsers.push_back(ParseKey);
293     proxy.ParseInputs(parsers);
294 
295     return proxy.DoAsyncWork(
296         "HasKey",
297         [](PreferencesAysncContext *asyncContext) {
298             PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(asyncContext->boundObj);
299             asyncContext->hasKey = obj->value_->HasKey(asyncContext->key);
300 
301             return OK;
302         },
303         [](PreferencesAysncContext *asyncContext, napi_value &output) {
304             napi_status status = napi_get_boolean(asyncContext->env, asyncContext->hasKey, &output);
305             return (status == napi_ok) ? OK : ERR;
306         });
307 }
308 
Flush(napi_env env,napi_callback_info info)309 napi_value PreferencesProxy::Flush(napi_env env, napi_callback_info info)
310 {
311     NapiAsyncProxy<PreferencesAysncContext> proxy;
312     proxy.Init(env, info);
313     std::vector<NapiAsyncProxy<PreferencesAysncContext>::InputParser> parsers;
314     proxy.ParseInputs(parsers);
315 
316     return proxy.DoAsyncWork(
317         "Flush",
318         [](PreferencesAysncContext *asyncContext) {
319             PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(asyncContext->boundObj);
320             return obj->value_->FlushSync();
321         },
322         [](PreferencesAysncContext *asyncContext, napi_value &output) {
323             napi_status status = napi_get_undefined(asyncContext->env, &output);
324             return (status == napi_ok) ? OK : ERR;
325         });
326 }
327 
Clear(napi_env env,napi_callback_info info)328 napi_value PreferencesProxy::Clear(napi_env env, napi_callback_info info)
329 {
330     NapiAsyncProxy<PreferencesAysncContext> proxy;
331     proxy.Init(env, info);
332     std::vector<NapiAsyncProxy<PreferencesAysncContext>::InputParser> parsers;
333     proxy.ParseInputs(parsers);
334 
335     return proxy.DoAsyncWork(
336         "Clear",
337         [](PreferencesAysncContext *asyncContext) {
338             PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(asyncContext->boundObj);
339             return obj->value_->Clear();
340         },
341         [](PreferencesAysncContext *asyncContext, napi_value &output) {
342             napi_status status = napi_get_undefined(asyncContext->env, &output);
343             return (status == napi_ok) ? OK : ERR;
344         });
345 }
346 
RegisterObserver(napi_env env,napi_callback_info info)347 napi_value PreferencesProxy::RegisterObserver(napi_env env, napi_callback_info info)
348 {
349     napi_value thiz = nullptr;
350     size_t argc = 2;
351     napi_value args[2] = { 0 };
352 
353     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
354     napi_valuetype type;
355     NAPI_CALL(env, napi_typeof(env, args[0], &type));
356     NAPI_ASSERT(env, type == napi_string, "key not string type");
357 
358     NAPI_CALL(env, napi_typeof(env, args[1], &type));
359     NAPI_ASSERT(env, type == napi_function, "observer not function type");
360 
361     PreferencesProxy *obj = nullptr;
362     NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
363 
364     // reference save
365     obj->observer_ = std::make_shared<PreferencesObserverImpl>(env, args[1]);
366     obj->value_->RegisterObserver(obj->observer_);
367     LOG_DEBUG("RegisterObserver end");
368 
369     return nullptr;
370 }
371 
UnRegisterObserver(napi_env env,napi_callback_info info)372 napi_value PreferencesProxy::UnRegisterObserver(napi_env env, napi_callback_info info)
373 {
374     napi_value thiz = nullptr;
375     size_t argc = 2;
376     napi_value args[2] = { 0 };
377 
378     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
379     napi_valuetype type;
380     NAPI_CALL(env, napi_typeof(env, args[0], &type));
381     NAPI_ASSERT(env, type == napi_string, "key not string type");
382 
383     NAPI_CALL(env, napi_typeof(env, args[1], &type));
384     NAPI_ASSERT(env, type == napi_function, "observer not function type");
385 
386     PreferencesProxy *obj = nullptr;
387     NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
388     obj->value_->UnRegisterObserver(obj->observer_);
389     obj->observer_.reset();
390     obj->observer_ = nullptr;
391     LOG_DEBUG("UnRegisterObserver end");
392     return nullptr;
393 }
394 
PreferencesObserverImpl(napi_env env,napi_value callback)395 PreferencesObserverImpl::PreferencesObserverImpl(napi_env env, napi_value callback) : observerRef(nullptr)
396 {
397     this->env_ = env;
398     napi_create_reference(env_, callback, 1, &observerRef);
399 }
400 
~PreferencesObserverImpl()401 PreferencesObserverImpl::~PreferencesObserverImpl()
402 {
403     napi_delete_reference(env_, observerRef);
404 }
405 
OnChange(Preferences & preferences,const std::string & key)406 void PreferencesObserverImpl::OnChange(Preferences &preferences, const std::string &key)
407 {
408     LOG_DEBUG("OnChange key:%{public}s", key.c_str());
409     napi_value callback = nullptr;
410     napi_value global = nullptr;
411     napi_value result = nullptr;
412     napi_value args[1] = { 0 };
413 
414     napi_create_string_utf8(env_, key.c_str(), key.size(), &args[0]);
415     napi_get_reference_value(env_, observerRef, &callback);
416     napi_get_global(env_, &global);
417 
418     napi_call_function(env_, global, callback, 1, args, &result);
419     LOG_DEBUG("OnChange key end");
420 }
421 } // namespace PreferencesJsKit
422 } // namespace OHOS
423