• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_system_storage.h"
17 
18 #include <string>
19 
20 #include "js_ability.h"
21 #include "log_print.h"
22 #include "js_utils.h"
23 #include "preferences_errno.h"
24 #include "preferences_helper.h"
25 
26 using namespace OHOS::NativePreferences;
27 
28 namespace OHOS {
29 namespace PreferencesJsKit {
30 struct AsyncContext {
31     std::string key;
32     std::string def;
33     std::string val;
34     std::string prefName;
35     napi_ref success;
36     napi_ref fail;
37     napi_ref complete;
38     napi_deferred deferred = nullptr;
39     int32_t output = E_ERROR;
40     napi_async_work request;
41 };
42 
43 static constexpr uint32_t MAX_KEY_LENGTH = 32;
44 
45 static constexpr uint32_t MAX_VALUE_LENGTH = 128;
46 
47 static constexpr uint32_t FAILCOUNT = 2;
48 
49 static constexpr uint32_t SUCCOUNT = 1;
50 
51 static constexpr int E_KEY_EMPTY_STSTEM_STORAGE = -1006;
52 
53 static constexpr int E_KEY_EXCEED_LENGTH_LIMIT_STSTEM_STORAGE = -1016;
54 
55 static constexpr int E_VALUE_EXCEED_LENGTH_LIMIT_STSTEM_STORAGE = -1017;
56 
57 static constexpr int E_DEFAULT_EXCEED_LENGTH_LIMIT_STSTEM_STORAGE = -1018;
58 
ParseString(napi_env env,napi_value object,const char * name,const bool enable,std::string & output)59 void ParseString(napi_env env, napi_value object, const char *name, const bool enable, std::string &output)
60 {
61     napi_value value = nullptr;
62     bool exist = false;
63     napi_has_named_property(env, object, name, &exist);
64     if (exist && (napi_get_named_property(env, object, name, &value) == napi_ok)) {
65         std::string key = "";
66         int32_t ret = JSUtils::Convert2NativeValue(env, value, key);
67         NAPI_ASSERT_RETURN_VOID(env, enable || (ret == E_OK && !key.empty()), "StorageOptions is empty.");
68         output = std::move(key);
69     }
70 }
71 
ParseFunction(napi_env env,napi_value object,const char * name,napi_ref & output)72 void ParseFunction(napi_env env, napi_value object, const char *name, napi_ref &output)
73 {
74     napi_value value = nullptr;
75     bool exist = false;
76     napi_has_named_property(env, object, name, &exist);
77     if (exist && (napi_get_named_property(env, object, name, &value) == napi_ok)) {
78         napi_valuetype valueType = napi_null;
79         NAPI_ASSERT_RETURN_VOID(env, value != nullptr, "value == nullptr");
80         NAPI_CALL_RETURN_VOID(env, napi_typeof(env, value, &valueType));
81         NAPI_ASSERT_RETURN_VOID(env, valueType == napi_function, "Wrong argument, function expected.");
82         NAPI_CALL_RETURN_VOID(env, napi_create_reference(env, value, 1, &output));
83     }
84 }
85 
GetMessageInfo(const int & errCode)86 const std::string GetMessageInfo(const int &errCode)
87 {
88     switch (errCode) {
89         case E_KEY_EMPTY:
90             return "The key string is null or empty.";
91         case E_KEY_EXCEED_LENGTH_LIMIT:
92             return "The key string length should shorter than 32.";
93         case E_VALUE_EXCEED_LENGTH_LIMIT:
94             return "The value string length should shorter than 128.";
95         case E_DEFAULT_EXCEED_LENGTH_LIMIT:
96             return "The default string length should shorter than 128.";
97         default:
98             return "unknown err";
99     }
100 }
101 
ConversionToSysStorageErrorCode(const int & errCode)102 int32_t ConversionToSysStorageErrorCode(const int &errCode)
103 {
104     switch (errCode) {
105         case E_KEY_EMPTY:
106             return E_KEY_EMPTY_STSTEM_STORAGE;
107         case E_KEY_EXCEED_LENGTH_LIMIT:
108             return E_KEY_EXCEED_LENGTH_LIMIT_STSTEM_STORAGE;
109         case E_VALUE_EXCEED_LENGTH_LIMIT:
110             return E_VALUE_EXCEED_LENGTH_LIMIT_STSTEM_STORAGE;
111         case E_DEFAULT_EXCEED_LENGTH_LIMIT:
112             return E_DEFAULT_EXCEED_LENGTH_LIMIT_STSTEM_STORAGE;
113         default:
114             return errCode;
115     }
116 }
117 
Complete(napi_env env,napi_status status,void * data)118 void Complete(napi_env env, napi_status status, void *data)
119 {
120     AsyncContext *ctx = static_cast<AsyncContext *>(data);
121     if (status != napi_ok) {
122         napi_throw_type_error(env, nullptr, "Execute callback failed.");
123         return;
124     }
125     size_t len = 0;
126     if (ctx->output == E_OK && ctx->success != nullptr) {
127         napi_value successCallBack = nullptr;
128         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, ctx->success, &successCallBack));
129         napi_value succRes[SUCCOUNT] = { 0 };
130         len = ctx->val.size();
131         NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, ctx->val.c_str(), len, &succRes[0]));
132         napi_value succCallbackResult = nullptr;
133         NAPI_CALL_RETURN_VOID(
134             env, napi_call_function(env, nullptr, successCallBack, SUCCOUNT, succRes, &succCallbackResult));
135     }
136 
137     if (ctx->output != E_OK && ctx->fail != nullptr) {
138         napi_value failCallBack = nullptr;
139         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, ctx->fail, &failCallBack));
140         napi_value failRes[FAILCOUNT] = { 0 };
141         std::string message = GetMessageInfo(ctx->output);
142         len = message.size();
143         NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, message.c_str(), len, &failRes[0]));
144         NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, ConversionToSysStorageErrorCode(ctx->output), &failRes[1]));
145         napi_value failCallbackResult = nullptr;
146         NAPI_CALL_RETURN_VOID(
147             env, napi_call_function(env, nullptr, failCallBack, FAILCOUNT, failRes, &failCallbackResult));
148     }
149 
150     if (ctx->complete != nullptr) {
151         napi_value completeCallBack = nullptr;
152         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, ctx->complete, &completeCallBack));
153         napi_value completeCallbackResult = nullptr;
154         NAPI_CALL_RETURN_VOID(
155             env, napi_call_function(env, nullptr, completeCallBack, 0, nullptr, &completeCallbackResult));
156     }
157     napi_delete_async_work(env, ctx->request);
158     napi_delete_reference(env, ctx->success);
159     napi_delete_reference(env, ctx->fail);
160     napi_delete_reference(env, ctx->complete);
161     napi_value res = nullptr;
162     napi_get_undefined(env, &res);
163     napi_resolve_deferred(env, ctx->deferred, res);
164     delete ctx;
165 }
166 
GetPrefName(napi_env env)167 std::string GetPrefName(napi_env env)
168 {
169     ContextInfo contextInfo;
170     JSAbility::GetContextInfo(env, nullptr, "", false, contextInfo);
171     return contextInfo.preferencesDir + "/default.xml";
172 }
173 
Operate(napi_env env,napi_callback_info info,const char * resource,bool parseStrFlag,napi_async_execute_callback execute)174 napi_value Operate(napi_env env, napi_callback_info info, const char *resource, bool parseStrFlag,
175     napi_async_execute_callback execute)
176 {
177     size_t argc = 1;
178     napi_value argv[1] = { 0 };
179     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
180     NAPI_ASSERT(env, argc == 1, "Not enough arguments, expected 1.");
181     napi_valuetype valueType = napi_null;
182     NAPI_CALL(env, napi_typeof(env, argv[0], &valueType));
183     NAPI_ASSERT(env, valueType == napi_object, "Wrong argument type, object expected.");
184 
185     AsyncContext *context = new (std::nothrow) AsyncContext();
186     if (context == nullptr) {
187         LOG_ERROR("Operate new failed, context is nullptr");
188         return nullptr;
189     }
190     context->prefName = GetPrefName(env);
191 
192     ParseString(env, argv[0], "key", parseStrFlag, context->key);
193     ParseString(env, argv[0], "value", false, context->val);
194     ParseString(env, argv[0], "default", false, context->def);
195 
196     ParseFunction(env, argv[0], "success", context->success);
197     ParseFunction(env, argv[0], "fail", context->fail);
198     ParseFunction(env, argv[0], "complete", context->complete);
199 
200     napi_value ret = nullptr;
201     napi_value resourceName = nullptr;
202     napi_status status = napi_create_string_utf8(env, resource, NAPI_AUTO_LENGTH, &resourceName);
203     if (status != napi_ok) {
204         LOG_ERROR("Operate get resourceName failed, status = %{public}d", status);
205         delete context;
206         return ret;
207     }
208     status = napi_create_promise(env, &context->deferred, &ret);
209     if (status != napi_ok) {
210         LOG_ERROR("Operate create promise failed, status = %{public}d", status);
211         delete context;
212         return ret;
213     }
214     status = napi_create_async_work(env, nullptr, resourceName, execute, Complete, context, &context->request);
215     if (status != napi_ok) {
216         LOG_ERROR("Operate create asyncWork failed, status = %{public}d", status);
217         delete context;
218         return ret;
219     }
220     status = napi_queue_async_work(env, context->request);
221     if (status != napi_ok) {
222         LOG_ERROR("Operate queue asyncWork failed, status = %{public}d", status);
223         delete context;
224     }
225     return ret;
226 }
227 
NapiGet(napi_env env,napi_callback_info info)228 napi_value NapiGet(napi_env env, napi_callback_info info)
229 {
230     return Operate(env, info, "get", true, [](napi_env env, void *data) {
231         AsyncContext *context = static_cast<AsyncContext *>(data);
232         if (context->key.size() > MAX_KEY_LENGTH) {
233             context->output = E_KEY_EXCEED_LENGTH_LIMIT;
234             return;
235         }
236 
237         if (context->def.size() > MAX_VALUE_LENGTH) {
238             context->output = E_DEFAULT_EXCEED_LENGTH_LIMIT;
239             return;
240         }
241 
242         auto pref = PreferencesHelper::GetPreferences(context->prefName, context->output);
243         context->val = pref->GetString(context->key, context->def);
244     });
245 }
246 
NapiSet(napi_env env,napi_callback_info info)247 napi_value NapiSet(napi_env env, napi_callback_info info)
248 {
249     return Operate(env, info, "set", true, [](napi_env env, void *data) {
250         AsyncContext *context = static_cast<AsyncContext *>(data);
251         if (context->key.size() > MAX_KEY_LENGTH) {
252             context->output = E_KEY_EXCEED_LENGTH_LIMIT;
253             return;
254         }
255         if (context->val.size() > MAX_VALUE_LENGTH) {
256             context->output = E_VALUE_EXCEED_LENGTH_LIMIT;
257             return;
258         }
259 
260         auto pref = PreferencesHelper::GetPreferences(context->prefName, context->output);
261         if (context->output != E_OK) {
262             return;
263         }
264         context->output = pref->PutString(context->key, context->val);
265         pref->FlushSync();
266     });
267 }
268 
NapiDelete(napi_env env,napi_callback_info info)269 napi_value NapiDelete(napi_env env, napi_callback_info info)
270 {
271     return Operate(env, info, "delete", true, [](napi_env env, void *data) {
272         AsyncContext *context = static_cast<AsyncContext *>(data);
273         if (context->key.size() > MAX_KEY_LENGTH) {
274             context->output = E_KEY_EXCEED_LENGTH_LIMIT;
275             return;
276         }
277 
278         auto pref = PreferencesHelper::GetPreferences(context->prefName, context->output);
279         if (context->output != E_OK) {
280             return;
281         }
282         context->output = pref->Delete(context->key);
283         pref->FlushSync();
284     });
285 }
286 
NapiClear(napi_env env,napi_callback_info info)287 napi_value NapiClear(napi_env env, napi_callback_info info)
288 {
289     return Operate(env, info, "clear", false, [](napi_env env, void *data) {
290         AsyncContext *context = static_cast<AsyncContext *>(data);
291         auto pref = PreferencesHelper::GetPreferences(context->prefName, context->output);
292         if (context->output != E_OK) {
293             return;
294         }
295         context->output = pref->Clear();
296         pref->FlushSync();
297     });
298 }
299 
InitSystemStorage(napi_env env,napi_value exports)300 napi_value InitSystemStorage(napi_env env, napi_value exports)
301 {
302     napi_property_descriptor properties[] = {
303         DECLARE_NAPI_FUNCTION("get", NapiGet),
304         DECLARE_NAPI_FUNCTION("delete", NapiDelete),
305         DECLARE_NAPI_FUNCTION("clear", NapiClear),
306         DECLARE_NAPI_FUNCTION("set", NapiSet),
307     };
308     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(*properties), properties));
309     return exports;
310 }
311 } // namespace PreferencesJsKit
312 } // namespace OHOS