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