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