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 #include "native_parameters_js.h"
16 #include "securec.h"
17 
18 static constexpr int MAX_LENGTH = 128;
19 static constexpr int ARGC_NUMBER = 2;
20 static constexpr int ARGC_THREE_NUMBER = 3;
21 static constexpr int BUF_LENGTH = 256;
22 
23 using StorageAsyncContext = struct StorageAsyncContext {
24     napi_env env = nullptr;
25     napi_async_work work = nullptr;
26 
27     char key[BUF_LENGTH] = { 0 };
28     size_t keyLen = 0;
29     char value[BUF_LENGTH] = { 0 };
30     size_t valueLen = 0;
31     napi_deferred deferred = nullptr;
32     napi_ref callbackRef = nullptr;
33 
34     int status = -1;
35     std::string getValue;
36 };
37 
38 using StorageAsyncContextPtr = StorageAsyncContext *;
39 
SetCallbackWork(napi_env env,StorageAsyncContextPtr asyncContext)40 static void SetCallbackWork(napi_env env, StorageAsyncContextPtr asyncContext)
41 {
42     napi_value resource = nullptr;
43     napi_create_string_utf8(env, "JSStartupSet", NAPI_AUTO_LENGTH, &resource);
44     napi_create_async_work(
45         env, nullptr, resource,
46         [](napi_env env, void *data) {
47             StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
48             asyncContext->status = SetParameter(asyncContext->key, asyncContext->value);
49             PARAM_JS_LOGV("JSApp set::asyncContext-> status = %d, asyncContext->key = %s, asyncContext->value = %s.",
50                 asyncContext->status, asyncContext->key, asyncContext->value);
51         },
52         [](napi_env env, napi_status status, void *data) {
53             StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
54             napi_value result[ARGC_NUMBER] = { 0 };
55             if (asyncContext->status == 0) {
56                 napi_get_undefined(env, &result[0]);
57                 napi_get_undefined(env, &result[1]);
58             } else {
59                 napi_value value = nullptr;
60                 napi_create_object(env, &result[0]);
61                 napi_create_int32(env, asyncContext->status, &value);
62                 napi_set_named_property(env, result[0], "code", value);
63                 napi_get_undefined(env, &result[1]);
64             }
65 
66             if (asyncContext->deferred) {
67                 if (asyncContext->status == 0) {
68                     napi_resolve_deferred(env, asyncContext->deferred, result[1]);
69                 } else {
70                     napi_reject_deferred(env, asyncContext->deferred, result[0]);
71                 }
72             } else {
73                 napi_value callback = nullptr;
74                 napi_value callResult = nullptr;
75                 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
76                 napi_call_function(env, nullptr, callback, ARGC_NUMBER, result, &callResult);
77                 napi_delete_reference(env, asyncContext->callbackRef);
78             }
79             napi_delete_async_work(env, asyncContext->work);
80             delete asyncContext;
81         },
82         reinterpret_cast<void *>(asyncContext), &asyncContext->work);
83     napi_queue_async_work(env, asyncContext->work);
84 }
85 
Set(napi_env env,napi_callback_info info)86 static napi_value Set(napi_env env, napi_callback_info info)
87 {
88     size_t argc = ARGC_THREE_NUMBER;
89     napi_value argv[ARGC_THREE_NUMBER] = { nullptr };
90     napi_value thisVar = nullptr;
91     void *data = nullptr;
92     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
93     NAPI_ASSERT(env, argc >= ARGC_NUMBER, "requires 2 parameter");
94     StorageAsyncContextPtr asyncContext = new StorageAsyncContext();
95     asyncContext->env = env;
96     for (size_t i = 0; i < argc; i++) {
97         napi_valuetype valueType = napi_null;
98         napi_typeof(env, argv[i], &valueType);
99 
100         if (i == 0 && valueType == napi_string) {
101             napi_get_value_string_utf8(env, argv[i], asyncContext->key,
102                 BUF_LENGTH - 1, &asyncContext->keyLen);
103         } else if (i == 1 && valueType == napi_string) {
104             napi_get_value_string_utf8(env, argv[i], asyncContext->value,
105                 BUF_LENGTH - 1, &asyncContext->valueLen);
106         } else if (i == ARGC_NUMBER && valueType == napi_function) {
107             napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
108         } else {
109             delete asyncContext;
110             NAPI_ASSERT(env, false, "type mismatch");
111         }
112     }
113 
114     napi_value result = nullptr;
115     if (asyncContext->callbackRef == nullptr) {
116         napi_create_promise(env, &asyncContext->deferred, &result);
117     } else {
118         napi_get_undefined(env, &result);
119     }
120 
121     SetCallbackWork(env, asyncContext);
122     return result;
123 }
124 
SetSync(napi_env env,napi_callback_info info)125 static napi_value SetSync(napi_env env, napi_callback_info info)
126 {
127     size_t argc = ARGC_NUMBER;
128     napi_value args[ARGC_NUMBER] = { nullptr };
129     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
130     NAPI_ASSERT(env, argc == ARGC_NUMBER, "Wrong number of arguments");
131     napi_valuetype valuetype0 = napi_null;
132     NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
133     napi_valuetype valuetype1 = napi_null;
134     NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
135     NAPI_ASSERT(env, valuetype0 == napi_string && valuetype1 == napi_string, "Wrong argument type. string expected.");
136 
137     char keyBuf[BUF_LENGTH] = { 0 };
138     size_t keySize = 0;
139     NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], keyBuf, BUF_LENGTH - 1, &keySize));
140     if (keySize >= MAX_LENGTH) {
141         return nullptr;
142     }
143 
144     char valueBuf[BUF_LENGTH] = { 0 };
145     size_t valueSize = 0;
146     NAPI_CALL(env, napi_get_value_string_utf8(env, args[1], valueBuf, BUF_LENGTH - 1, &valueSize));
147     if (valueSize >= MAX_LENGTH) {
148         return nullptr;
149     }
150 
151     std::string keyStr = keyBuf;
152     std::string valueStr = valueBuf;
153     int setResult = SetParameter(keyStr.c_str(), valueStr.c_str());
154     PARAM_JS_LOGV("JSApp SetSync::setResult = %d, input keyBuf = %s.", setResult, keyBuf);
155 
156     napi_value napiValue = nullptr;
157     if (setResult != 0) { // set failed
158         std::stringstream ss;
159         ss << "set: " << keyStr << " failed, error code: " << setResult;
160         napi_throw_error((env), nullptr, ss.str().c_str());
161     } else {
162         napi_get_undefined(env, &napiValue);
163     }
164     return napiValue;
165 }
166 
GetSync(napi_env env,napi_callback_info info)167 static napi_value GetSync(napi_env env, napi_callback_info info)
168 {
169     size_t argc = ARGC_NUMBER;
170     napi_value args[ARGC_NUMBER] = { nullptr };
171     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
172     NAPI_ASSERT(env, argc == 1 || argc == ARGC_NUMBER, "Wrong number of arguments");
173     napi_valuetype valuetype0 = napi_null;
174     NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
175     NAPI_ASSERT(env, valuetype0 == napi_string, "Wrong argument type. Numbers expected.");
176 
177     napi_valuetype valuetype1 = napi_null;
178     if (argc == ARGC_NUMBER) {
179         NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
180         NAPI_ASSERT(env, (valuetype1 == napi_string) || (valuetype1 == napi_undefined),
181             "Wrong argument type. string expected.");
182     }
183 
184     char keyBuf[BUF_LENGTH] = { 0 };
185     size_t keySize = 0;
186     NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], keyBuf, BUF_LENGTH - 1, &keySize));
187     if (keySize >= MAX_LENGTH) {
188         return nullptr;
189     }
190 
191     std::string keyStr = keyBuf;
192     std::string valueStr = "";
193     std::string getValue = "";
194     if (argc == ARGC_NUMBER) {
195         char valueBuf[BUF_LENGTH] = { 0 };
196         size_t valueSize = 0;
197         if (valuetype1 == napi_undefined) {
198             valueStr = "";
199         } else {
200             NAPI_CALL(env, napi_get_value_string_utf8(env, args[1], valueBuf, BUF_LENGTH - 1, &valueSize));
201             if (valueSize >= MAX_LENGTH) {
202                 return nullptr;
203             }
204             valueStr = valueBuf;
205         }
206     }
207     int ret = OHOS::system::GetStringParameter(keyStr, getValue, valueStr);
208     PARAM_JS_LOGV("JSApp GetSync::getValue = %s, input keyStr = %s.", getValue.c_str(), keyBuf);
209 
210     napi_value napiValue = nullptr;
211     if (ret == 0) {
212         NAPI_CALL(env, napi_create_string_utf8(env, getValue.c_str(), strlen(getValue.c_str()), &napiValue));
213     }
214     return napiValue;
215 }
216 
GetCallbackWork(napi_env env,StorageAsyncContextPtr asyncContext)217 static void GetCallbackWork(napi_env env, StorageAsyncContextPtr asyncContext)
218 {
219     napi_value resource = nullptr;
220     napi_create_string_utf8(env, "JSStartupGet", NAPI_AUTO_LENGTH, &resource);
221     napi_create_async_work(
222         env, nullptr, resource,
223         [](napi_env env, void *data) {
224             StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
225             asyncContext->status =
226                 OHOS::system::GetStringParameter(asyncContext->key, asyncContext->getValue, asyncContext->value);
227             PARAM_JS_LOGV("JSApp get status = %d, asyncContext->getValue = %s, asyncContext->key = %s, value = %s.",
228                 asyncContext->status, asyncContext->getValue.c_str(), asyncContext->key, asyncContext->value);
229         },
230         [](napi_env env, napi_status status, void *data) {
231             StorageAsyncContext *asyncContext = reinterpret_cast<StorageAsyncContext *>(data);
232             napi_value result[ARGC_NUMBER] = { 0 };
233             if (asyncContext->status == 0) {
234                 napi_get_undefined(env, &result[0]);
235                 napi_create_string_utf8(env, asyncContext->getValue.c_str(), strlen(asyncContext->getValue.c_str()),
236                     &result[1]);
237             } else {
238                 napi_value message = nullptr;
239                 napi_create_object(env, &result[0]);
240                 napi_create_int32(env, asyncContext->status, &message);
241                 napi_set_named_property(env, result[0], "code", message);
242                 napi_get_undefined(env, &result[1]);
243             }
244 
245             if (asyncContext->deferred) {
246                 if (asyncContext->status == 0) {
247                     napi_resolve_deferred(env, asyncContext->deferred, result[1]);
248                 } else {
249                     napi_reject_deferred(env, asyncContext->deferred, result[0]);
250                 }
251             } else {
252                 napi_value callback = nullptr;
253                 napi_value callResult = nullptr;
254                 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
255                 napi_call_function(env, nullptr, callback, ARGC_NUMBER, result, &callResult);
256                 napi_delete_reference(env, asyncContext->callbackRef);
257             }
258             napi_delete_async_work(env, asyncContext->work);
259             delete asyncContext;
260         },
261         reinterpret_cast<void *>(asyncContext), &asyncContext->work);
262     napi_queue_async_work(env, asyncContext->work);
263 }
264 
Get(napi_env env,napi_callback_info info)265 static napi_value Get(napi_env env, napi_callback_info info)
266 {
267     size_t argc = ARGC_THREE_NUMBER;
268     napi_value argv[ARGC_THREE_NUMBER] = { nullptr };
269     napi_value thisVar = nullptr;
270     void *data = nullptr;
271     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
272     NAPI_ASSERT(env, argc >= 1, "requires 1 parameter");
273     StorageAsyncContextPtr asyncContext = new StorageAsyncContext();
274     asyncContext->env = env;
275     for (size_t i = 0; i < argc; i++) {
276         napi_valuetype valueType = napi_null;
277         napi_typeof(env, argv[i], &valueType);
278 
279         if (i == 0 && valueType == napi_string) {
280             napi_get_value_string_utf8(env, argv[i], asyncContext->key,
281                 BUF_LENGTH - 1, &asyncContext->keyLen);
282         } else if (i == 1 && valueType == napi_string) {
283             napi_get_value_string_utf8(env, argv[i], asyncContext->value,
284                 BUF_LENGTH - 1, &asyncContext->valueLen);
285         } else if (i == 1 && valueType == napi_undefined) {
286             strcpy_s(asyncContext->value, BUF_LENGTH, "\0");
287         } else if (i == 1 && valueType == napi_function) {
288             napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
289             break;
290         } else if (i == ARGC_NUMBER && valueType == napi_function) {
291             napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
292         } else {
293             delete asyncContext;
294             NAPI_ASSERT(env, false, "type mismatch");
295         }
296     }
297 
298     napi_value result = nullptr;
299     if (asyncContext->callbackRef == nullptr) {
300         napi_create_promise(env, &asyncContext->deferred, &result);
301     } else {
302         napi_get_undefined(env, &result);
303     }
304 
305     GetCallbackWork(env, asyncContext);
306     return result;
307 }
308 
309 EXTERN_C_START
310 /*
311  * Module init
312  */
Init(napi_env env,napi_value exports)313 static napi_value Init(napi_env env, napi_value exports)
314 {
315     /*
316      * Attribute definition
317      */
318     napi_property_descriptor desc[] = {
319         DECLARE_NAPI_FUNCTION("set", Set),
320         DECLARE_NAPI_FUNCTION("setSync", SetSync),
321         DECLARE_NAPI_FUNCTION("get", Get),
322         DECLARE_NAPI_FUNCTION("getSync", GetSync),
323         DECLARE_NAPI_FUNCTION("wait", ParamWait),
324         DECLARE_NAPI_FUNCTION("getWatcher", GetWatcher)
325     };
326     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
327     return RegisterWatcher(env, exports);
328 }
329 EXTERN_C_END
330 
331 /*
332  * Module definition
333  */
334 static napi_module _module = {
335     .nm_version = 1,
336     .nm_flags = 0,
337     .nm_filename = NULL,
338     .nm_register_func = Init,
339     .nm_modname = "systemparameter",
340     .nm_priv = ((void *)0),
341     .reserved = { 0 }
342 };
343 
344 /*
345  * Module registration function
346  */
RegisterModule(void)347 extern "C" __attribute__((constructor)) void RegisterModule(void)
348 {
349     napi_module_register(&_module);
350 }
351