• 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_utils.h"
17 #include "time_common.h"
18 #include "time_service_client.h"
19 
20 namespace OHOS {
21 namespace MiscServicesNapi {
22 using namespace OHOS::MiscServices;
23 using namespace OHOS::MiscServices::Time;
24 typedef struct AsyncContext {
~AsyncContextOHOS::MiscServicesNapi::AsyncContext25     ~AsyncContext()
26     {
27         if (callbackRef != nullptr) {
28             napi_delete_reference(env, callbackRef);
29         }
30     }
31     napi_env env = nullptr;
32     napi_async_work work = nullptr;
33     int64_t time = INVALID_TIME;
34     std::string timeZone = "";
35     napi_deferred deferred = nullptr;
36     napi_ref callbackRef = nullptr;
37     bool isCallback = false;
38     bool isOK = false;
39     bool isNano = false;
40     int32_t errorCode = E_TIME_OK;
41     std::string message = "system error";
42 } AsyncContext;
43 
FreeWorkIfFail(napi_status status,napi_env env,AsyncContext * asyncContext)44 void FreeWorkIfFail(napi_status status, napi_env env, AsyncContext *asyncContext)
45 {
46     if (status != napi_ok) {
47         napi_delete_async_work(env, asyncContext->work);
48         delete asyncContext;
49         NAPI_CALL_RETURN_VOID(env, status);
50     }
51 }
52 
TimePaddingAsyncCallbackInfo(const napi_env & env,AsyncContext * & asynccallbackinfo,const napi_ref & callback,napi_value & promise)53 void TimePaddingAsyncCallbackInfo(const napi_env &env, AsyncContext *&asynccallbackinfo, const napi_ref &callback,
54     napi_value &promise)
55 {
56     if (callback) {
57         asynccallbackinfo->callbackRef = callback;
58         asynccallbackinfo->isCallback = true;
59     } else {
60         napi_deferred deferred = nullptr;
61         NAPI_CALL_RETURN_VOID(env, napi_create_promise(env, &deferred, &promise));
62         asynccallbackinfo->deferred = deferred;
63         asynccallbackinfo->isCallback = false;
64     }
65 }
66 
JSSystemTimeSetTime(napi_env env,napi_callback_info info)67 napi_value JSSystemTimeSetTime(napi_env env, napi_callback_info info)
68 {
69     size_t argc = SET_TIME_MAX_PARA;
70     napi_value argv[SET_TIME_MAX_PARA] = { 0 };
71     napi_value thisVar = nullptr;
72     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
73     int64_t times = INVALID_TIME;
74     napi_ref callback = nullptr;
75     if (NapiUtils::ParseParametersBySetTime(env, argv, argc, times, callback) == nullptr) {
76         return NapiUtils::GetUndefinedValue(env);
77     }
78     AsyncContext *asyncContext = new (std::nothrow) AsyncContext{ .env = env, .time = times };
79     if (!asyncContext) {
80         return NapiUtils::JSParaError(env, callback);
81     }
82     napi_value promise = nullptr;
83     TimePaddingAsyncCallbackInfo(env, asyncContext, callback, promise);
84     napi_value resource = nullptr;
85     napi_create_string_utf8(env, "JSSystemTimeSetTime", NAPI_AUTO_LENGTH, &resource);
86     napi_create_async_work(
87         env, nullptr, resource,
88         [](napi_env env, void *data) {
89             AsyncContext *asyncContext = (AsyncContext *)data;
90             int32_t errorCode = E_TIME_OK;
91             asyncContext->isOK = TimeServiceClient::GetInstance()->SetTime(asyncContext->time, errorCode);
92             if (!asyncContext->isOK) {
93                 auto jsErrorCode = NapiUtils::ConvertErrorCode(errorCode);
94                 asyncContext->message = NapiUtils::GetErrorMessage(jsErrorCode);
95                 asyncContext->errorCode = JsErrorCode::ERROR;
96             }
97         },
98         [](napi_env env, napi_status status, void *data) {
99             AsyncContext *asyncContext = (AsyncContext *)data;
100             if (asyncContext == nullptr) {
101                 return;
102             }
103             CallbackPromiseInfo info{ asyncContext->callbackRef, asyncContext->deferred, asyncContext->isCallback,
104                 asyncContext->errorCode, asyncContext->message };
105             napi_value result = 0;
106             napi_get_null(env, &result);
107             NapiUtils::ReturnCallbackPromise(env, info, result);
108             napi_delete_async_work(env, asyncContext->work);
109             delete asyncContext;
110         },
111         (void *)asyncContext, &asyncContext->work);
112     bool isCallback = asyncContext->isCallback;
113     FreeWorkIfFail(
114         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated), env, asyncContext);
115     return isCallback ? NapiUtils::NapiGetNull(env) : promise;
116 }
117 
JSSystemTimeSetTimeZone(napi_env env,napi_callback_info info)118 napi_value JSSystemTimeSetTimeZone(napi_env env, napi_callback_info info)
119 {
120     size_t argc = SET_TIMEZONE_MAX_PARA;
121     napi_value argv[SET_TIMEZONE_MAX_PARA] = { 0 };
122     napi_value thisVar = nullptr;
123     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
124     std::string timezoneId;
125     napi_ref callback = nullptr;
126     if (NapiUtils::ParseParametersBySetTimezone(env, argv, argc, timezoneId, callback) == nullptr) {
127         return NapiUtils::GetUndefinedValue(env);
128     }
129     AsyncContext *asyncContext = new (std::nothrow) AsyncContext{ .env = env, .timeZone = timezoneId };
130     if (!asyncContext) {
131         return NapiUtils::JSParaError(env, callback);
132     }
133     napi_value promise = nullptr;
134     TimePaddingAsyncCallbackInfo(env, asyncContext, callback, promise);
135     napi_value resource = nullptr;
136     napi_create_string_utf8(env, "JSSystemTimeSetTimeZone", NAPI_AUTO_LENGTH, &resource);
137     napi_create_async_work(
138         env, nullptr, resource,
139         [](napi_env env, void *data) {
140             AsyncContext *asyncContext = (AsyncContext *)data;
141             int32_t errorCode = E_TIME_OK;
142             asyncContext->isOK = TimeServiceClient::GetInstance()->SetTimeZone(asyncContext->timeZone, errorCode);
143             if (!asyncContext->isOK) {
144                 auto jsErrorCode = NapiUtils::ConvertErrorCode(errorCode);
145                 asyncContext->message = NapiUtils::GetErrorMessage(jsErrorCode).c_str();
146                 asyncContext->errorCode = JsErrorCode::ERROR;
147             }
148         },
149         [](napi_env env, napi_status status, void *data) {
150             AsyncContext *asyncContext = (AsyncContext *)data;
151             if (asyncContext == nullptr) {
152                 return;
153             }
154             CallbackPromiseInfo info{ asyncContext->callbackRef, asyncContext->deferred, asyncContext->isCallback,
155                 asyncContext->errorCode, asyncContext->message };
156             napi_value result = 0;
157             napi_get_null(env, &result);
158             NapiUtils::ReturnCallbackPromise(env, info, result);
159             napi_delete_async_work(env, asyncContext->work);
160             delete asyncContext;
161         },
162         (void *)asyncContext, &asyncContext->work);
163     bool isCallback = asyncContext->isCallback;
164     FreeWorkIfFail(
165         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated), env, asyncContext);
166     return isCallback ? NapiUtils::NapiGetNull(env) : promise;
167 }
168 
JSSystemTimeGetCurrentTime(napi_env env,napi_callback_info info)169 napi_value JSSystemTimeGetCurrentTime(napi_env env, napi_callback_info info)
170 {
171     size_t argc = SET_TIMEZONE_MAX_PARA;
172     napi_value argv[SET_TIMEZONE_MAX_PARA] = { 0 };
173     napi_value thisVar = nullptr;
174     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
175     napi_ref callback = nullptr;
176     bool isNano = false;
177     if (NapiUtils::ParseParametersGetNA(env, argv, argc, callback, &isNano) == nullptr) {
178         return NapiUtils::GetUndefinedValue(env);
179     }
180     AsyncContext *asyncContext = new (std::nothrow) AsyncContext{ .env = env };
181     if (!asyncContext) {
182         return NapiUtils::JSParaError(env, callback);
183     }
184     napi_value promise = nullptr;
185     TimePaddingAsyncCallbackInfo(env, asyncContext, callback, promise);
186     asyncContext->isNano = isNano;
187     napi_value resource = nullptr;
188     napi_create_string_utf8(env, "JSSystemTimeGetCurrentTime", NAPI_AUTO_LENGTH, &resource);
189     napi_create_async_work(
190         env, nullptr, resource,
191         [](napi_env env, void *data) {
192             AsyncContext *asyncContext = (AsyncContext *)data;
193             if (asyncContext->isNano) {
194                 asyncContext->time = TimeServiceClient::GetInstance()->GetWallTimeNs();
195             } else {
196                 asyncContext->time = TimeServiceClient::GetInstance()->GetWallTimeMs();
197             }
198         },
199         [](napi_env env, napi_status status, void *data) {
200             AsyncContext *asyncContext = (AsyncContext *)data;
201             if (asyncContext == nullptr) {
202                 return;
203             }
204             if (asyncContext->time < 0) {
205                 asyncContext->errorCode = JsErrorCode::ERROR;
206             }
207             CallbackPromiseInfo info{ asyncContext->callbackRef, asyncContext->deferred, asyncContext->isCallback,
208                 asyncContext->errorCode, asyncContext->message };
209             napi_value result = nullptr;
210             napi_create_int64(env, asyncContext->time, &result);
211             NapiUtils::ReturnCallbackPromise(env, info, result);
212             napi_delete_async_work(env, asyncContext->work);
213             delete asyncContext;
214         },
215         (void *)asyncContext, &asyncContext->work);
216     bool isCallback = asyncContext->isCallback;
217     FreeWorkIfFail(
218         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated), env, asyncContext);
219     return isCallback ? NapiUtils::NapiGetNull(env) : promise;
220 }
221 
JSSystemTimeGetRealActiveTime(napi_env env,napi_callback_info info)222 napi_value JSSystemTimeGetRealActiveTime(napi_env env, napi_callback_info info)
223 {
224     size_t argc = SET_TIMEZONE_MAX_PARA;
225     napi_value argv[SET_TIMEZONE_MAX_PARA] = { 0 };
226     napi_value thisVar = nullptr;
227     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
228     napi_ref callback = nullptr;
229     bool isNano = false;
230     if (NapiUtils::ParseParametersGetNA(env, argv, argc, callback, &isNano) == nullptr) {
231         return NapiUtils::GetUndefinedValue(env);
232     }
233     AsyncContext *asyncContext = new (std::nothrow) AsyncContext{ .env = env };
234     if (!asyncContext) {
235         return NapiUtils::JSParaError(env, callback);
236     }
237     napi_value promise = nullptr;
238     TimePaddingAsyncCallbackInfo(env, asyncContext, callback, promise);
239     asyncContext->isNano = isNano;
240     napi_value resource = nullptr;
241     napi_create_string_utf8(env, "JSSystemTimeGetRealActiveTime", NAPI_AUTO_LENGTH, &resource);
242     napi_create_async_work(
243         env, nullptr, resource,
244         [](napi_env env, void *data) {
245             AsyncContext *asyncContext = (AsyncContext *)data;
246             if (asyncContext->isNano) {
247                 asyncContext->time = TimeServiceClient::GetInstance()->GetMonotonicTimeNs();
248             } else {
249                 asyncContext->time = TimeServiceClient::GetInstance()->GetMonotonicTimeMs();
250             }
251         },
252         [](napi_env env, napi_status status, void *data) {
253             AsyncContext *asyncContext = (AsyncContext *)data;
254             if (asyncContext == nullptr) {
255                 return;
256             }
257             if (asyncContext->time < 0) {
258                 asyncContext->errorCode = JsErrorCode::ERROR;
259             }
260             CallbackPromiseInfo info{ asyncContext->callbackRef, asyncContext->deferred, asyncContext->isCallback,
261                 asyncContext->errorCode, asyncContext->message };
262             napi_value result = nullptr;
263             napi_create_int64(env, asyncContext->time, &result);
264             NapiUtils::ReturnCallbackPromise(env, info, result);
265             napi_delete_async_work(env, asyncContext->work);
266             delete asyncContext;
267         },
268         (void *)asyncContext, &asyncContext->work);
269     bool isCallback = asyncContext->isCallback;
270     FreeWorkIfFail(
271         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated), env, asyncContext);
272     return isCallback ? NapiUtils::NapiGetNull(env) : promise;
273 }
274 
JSSystemTimeGetRealTime(napi_env env,napi_callback_info info)275 napi_value JSSystemTimeGetRealTime(napi_env env, napi_callback_info info)
276 {
277     size_t argc = SET_TIMEZONE_MAX_PARA;
278     napi_value argv[SET_TIMEZONE_MAX_PARA] = { 0 };
279     napi_value thisVar = nullptr;
280     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
281     napi_ref callback = nullptr;
282     bool isNano = false;
283     if (NapiUtils::ParseParametersGetNA(env, argv, argc, callback, &isNano) == nullptr) {
284         return NapiUtils::GetUndefinedValue(env);
285     }
286     AsyncContext *asyncContext = new (std::nothrow) AsyncContext{ .env = env };
287     if (!asyncContext) {
288         return NapiUtils::JSParaError(env, callback);
289     }
290     napi_value promise = nullptr;
291     TimePaddingAsyncCallbackInfo(env, asyncContext, callback, promise);
292     asyncContext->isNano = isNano;
293     napi_value resource = nullptr;
294     napi_create_string_utf8(env, "JSSystemTimeGetRealTime", NAPI_AUTO_LENGTH, &resource);
295     napi_create_async_work(
296         env, nullptr, resource,
297         [](napi_env env, void *data) {
298             AsyncContext *asyncContext = (AsyncContext *)data;
299             if (asyncContext->isNano) {
300                 asyncContext->time = TimeServiceClient::GetInstance()->GetBootTimeNs();
301             } else {
302                 asyncContext->time = TimeServiceClient::GetInstance()->GetBootTimeMs();
303             }
304         },
305         [](napi_env env, napi_status status, void *data) {
306             AsyncContext *asyncContext = (AsyncContext *)data;
307             if (asyncContext == nullptr) {
308                 return;
309             }
310             if (asyncContext->time < 0) {
311                 asyncContext->errorCode = JsErrorCode::ERROR;
312             }
313             CallbackPromiseInfo info{ asyncContext->callbackRef, asyncContext->deferred, asyncContext->isCallback,
314                 asyncContext->errorCode, asyncContext->message };
315             napi_value result = nullptr;
316             napi_create_int64(env, asyncContext->time, &result);
317             NapiUtils::ReturnCallbackPromise(env, info, result);
318             napi_delete_async_work(env, asyncContext->work);
319             delete asyncContext;
320         },
321         (void *)asyncContext, &asyncContext->work);
322     bool isCallback = asyncContext->isCallback;
323     FreeWorkIfFail(
324         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated), env, asyncContext);
325     return isCallback ? NapiUtils::NapiGetNull(env) : promise;
326 }
327 
JSSystemTimeGetDate(napi_env env,napi_callback_info info)328 napi_value JSSystemTimeGetDate(napi_env env, napi_callback_info info)
329 {
330     size_t argc = SET_TIMEZONE_MAX_PARA;
331     napi_value argv[SET_TIMEZONE_MAX_PARA] = { 0 };
332     napi_value thisVar = nullptr;
333     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
334     napi_ref callback = nullptr;
335     if (NapiUtils::ParseParametersGet(env, argv, argc, callback) == nullptr) {
336         return NapiUtils::GetUndefinedValue(env);
337     }
338     AsyncContext *asyncContext = new (std::nothrow) AsyncContext{ .env = env };
339     if (!asyncContext) {
340         return NapiUtils::JSParaError(env, callback);
341     }
342     napi_value promise = nullptr;
343     TimePaddingAsyncCallbackInfo(env, asyncContext, callback, promise);
344     napi_value resource = nullptr;
345     napi_create_string_utf8(env, "JSSystemTimeGetDate", NAPI_AUTO_LENGTH, &resource);
346     napi_create_async_work(
347         env, nullptr, resource,
348         [](napi_env env, void *data) {
349             AsyncContext *asyncContext = (AsyncContext *)data;
350             asyncContext->time = TimeServiceClient::GetInstance()->GetWallTimeMs();
351         },
352         [](napi_env env, napi_status status, void *data) {
353             AsyncContext *asyncContext = (AsyncContext *)data;
354             if (asyncContext == nullptr) {
355                 return;
356             }
357             if (asyncContext->time < 0) {
358                 asyncContext->errorCode = JsErrorCode::ERROR;
359             }
360             CallbackPromiseInfo info{ asyncContext->callbackRef, asyncContext->deferred, asyncContext->isCallback,
361                 asyncContext->errorCode, asyncContext->message };
362             napi_value result = nullptr;
363             napi_create_date(env, asyncContext->time, &result);
364             NapiUtils::ReturnCallbackPromise(env, info, result);
365             napi_delete_async_work(env, asyncContext->work);
366             delete asyncContext;
367         },
368         (void *)asyncContext, &asyncContext->work);
369     bool isCallback = asyncContext->isCallback;
370     FreeWorkIfFail(
371         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated), env, asyncContext);
372     return isCallback ? NapiUtils::NapiGetNull(env) : promise;
373 }
374 
JSSystemTimeGetTimeZone(napi_env env,napi_callback_info info)375 napi_value JSSystemTimeGetTimeZone(napi_env env, napi_callback_info info)
376 {
377     size_t argc = SET_TIMEZONE_MAX_PARA;
378     napi_value argv[SET_TIMEZONE_MAX_PARA] = { 0 };
379     napi_value thisVar = nullptr;
380     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
381     napi_ref callback = nullptr;
382     if (NapiUtils::ParseParametersGet(env, argv, argc, callback) == nullptr) {
383         return NapiUtils::GetUndefinedValue(env);
384     }
385     AsyncContext *asyncContext = new (std::nothrow) AsyncContext{ .env = env };
386     if (!asyncContext) {
387         return NapiUtils::JSParaError(env, callback);
388     }
389     napi_value promise = nullptr;
390     TimePaddingAsyncCallbackInfo(env, asyncContext, callback, promise);
391     napi_value resource = nullptr;
392     napi_create_string_utf8(env, "JSSystemTimeGetTimeZone", NAPI_AUTO_LENGTH, &resource);
393     napi_create_async_work(
394         env, nullptr, resource,
395         [](napi_env env, void *data) {
396             AsyncContext *asyncContext = (AsyncContext *)data;
397             asyncContext->timeZone = TimeServiceClient::GetInstance()->GetTimeZone();
398         },
399         [](napi_env env, napi_status status, void *data) {
400             AsyncContext *asyncContext = (AsyncContext *)data;
401             if (asyncContext == nullptr) {
402                 return;
403             }
404             if (asyncContext->timeZone == "") {
405                 asyncContext->errorCode = JsErrorCode::ERROR;
406             }
407             CallbackPromiseInfo info{ asyncContext->callbackRef, asyncContext->deferred, asyncContext->isCallback,
408                 asyncContext->errorCode, asyncContext->message };
409             napi_value result = nullptr;
410             napi_create_string_utf8(env, asyncContext->timeZone.c_str(), asyncContext->timeZone.length(), &result);
411             NapiUtils::ReturnCallbackPromise(env, info, result);
412             napi_delete_async_work(env, asyncContext->work);
413             delete asyncContext;
414         },
415         (void *)asyncContext, &asyncContext->work);
416     bool isCallback = asyncContext->isCallback;
417     FreeWorkIfFail(
418         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated), env, asyncContext);
419     return isCallback ? NapiUtils::NapiGetNull(env) : promise;
420 }
421 
422 EXTERN_C_START
SystemTimeExport(napi_env env,napi_value exports)423 napi_value SystemTimeExport(napi_env env, napi_value exports)
424 {
425     static napi_property_descriptor desc[] = {
426         DECLARE_NAPI_FUNCTION("setTime", JSSystemTimeSetTime),
427         DECLARE_NAPI_FUNCTION("setDate", JSSystemTimeSetTime),
428         DECLARE_NAPI_FUNCTION("setTimezone", JSSystemTimeSetTimeZone),
429         DECLARE_NAPI_FUNCTION("getCurrentTime", JSSystemTimeGetCurrentTime),
430         DECLARE_NAPI_FUNCTION("getRealActiveTime", JSSystemTimeGetRealActiveTime),
431         DECLARE_NAPI_FUNCTION("getRealTime", JSSystemTimeGetRealTime),
432         DECLARE_NAPI_FUNCTION("getDate", JSSystemTimeGetDate),
433         DECLARE_NAPI_FUNCTION("getTimezone", JSSystemTimeGetTimeZone),
434     };
435     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
436     return exports;
437 }
438 EXTERN_C_END
439 
440 static napi_module system_time_module = { .nm_version = 1,
441     .nm_flags = 0,
442     .nm_filename = nullptr,
443     .nm_register_func = SystemTimeExport,
444     .nm_modname = "systemTime",
445     .nm_priv = ((void *)0),
446     .reserved = { 0 } };
447 
SystemTimeRegister()448 extern "C" __attribute__((constructor)) void SystemTimeRegister()
449 {
450     napi_module_register(&system_time_module);
451 }
452 } // namespace MiscServicesNapi
453 } // namespace OHOS