• 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 <uv.h>
17 #include <memory>
18 #include <string>
19 #include <vector>
20 #include "timer_type.h"
21 #include "want_agent_helper.h"
22 #include "securec.h"
23 #include "system_timer.h"
24 
25 namespace OHOS {
26 namespace MiscServicesNapi {
27 namespace {
28 const int NO_ERROR = 0;
29 const int ERROR = -1;
30 const int CREATE_MAX_PARA = 2;
31 const int START_MAX_PARA = 3;
32 const int STOP_MAX_PARA = 2;
33 const int DESTROY_MAX_PARA = 2;
34 const int ARGS_TWO = 2;
35 const int PARAM0 = 0;
36 const int PARAM1 = 1;
37 }
38 
39 struct CallbackPromiseInfo {
40     napi_ref callback = nullptr;
41     napi_deferred deferred = nullptr;
42     bool isCallback = false;
43     int errorCode = 0;
44 };
45 
46 struct ReceiveDataWorker {
47     napi_env env = nullptr;
48     napi_ref ref = 0;
49 };
50 
51 struct AsyncCallbackInfoCreate {
~AsyncCallbackInfoCreateOHOS::MiscServicesNapi::AsyncCallbackInfoCreate52     ~AsyncCallbackInfoCreate()
53     {
54         if (callback != nullptr) {
55             napi_delete_reference(env, callback);
56         }
57     }
58     napi_env env = nullptr;
59     napi_async_work asyncWork = nullptr;
60     napi_ref callback = nullptr;
61     napi_deferred deferred = nullptr;
62     std::shared_ptr<ITimerInfoInstance> iTimerInfoInstance = nullptr;
63     uint64_t timerId = 0;
64     bool isCallback = false;
65     int errorCode = NO_ERROR;
66 };
67 
68 struct AsyncCallbackInfoStart {
~AsyncCallbackInfoStartOHOS::MiscServicesNapi::AsyncCallbackInfoStart69     ~AsyncCallbackInfoStart()
70     {
71         if (callback != nullptr) {
72             napi_delete_reference(env, callback);
73         }
74     }
75     napi_env env = nullptr;
76     napi_async_work asyncWork = nullptr;
77     napi_ref callback = nullptr;
78     napi_deferred deferred = nullptr;
79     uint64_t timerId = 0;
80     uint64_t triggerTime = 0;
81     bool isOK = false;
82     bool isCallback = false;
83     int errorCode = NO_ERROR;
84 };
85 
86 struct AsyncCallbackInfoStop {
~AsyncCallbackInfoStopOHOS::MiscServicesNapi::AsyncCallbackInfoStop87     ~AsyncCallbackInfoStop()
88     {
89         if (callback != nullptr) {
90             napi_delete_reference(env, callback);
91         }
92     }
93     napi_env env = nullptr;
94     napi_async_work asyncWork = nullptr;
95     napi_ref callback = nullptr;
96     napi_deferred deferred = nullptr;
97     uint64_t timerId = 0;
98     bool isOK = false;
99     bool isCallback = false;
100     int errorCode = NO_ERROR;
101 };
102 
103 struct AsyncCallbackInfoDestroy {
~AsyncCallbackInfoDestroyOHOS::MiscServicesNapi::AsyncCallbackInfoDestroy104     ~AsyncCallbackInfoDestroy()
105     {
106         if (callback != nullptr) {
107             napi_delete_reference(env, callback);
108         }
109     }
110     napi_env env = nullptr;
111     napi_async_work asyncWork = nullptr;
112     napi_ref callback = nullptr;
113     napi_deferred deferred = nullptr;
114     uint64_t timerId = 0;
115     bool isOK = false;
116     bool isCallback = false;
117     int errorCode = NO_ERROR;
118 };
119 
120 static std::vector<AsyncCallbackInfoCreate *> asyncCallbackInfoCreateInfo;
121 
NapiGetNull(napi_env env)122 napi_value NapiGetNull(napi_env env)
123 {
124     napi_value result = nullptr;
125     napi_get_null(env, &result);
126     return result;
127 }
128 
GetCallbackErrorValue(napi_env env,int errCode)129 napi_value GetCallbackErrorValue(napi_env env, int errCode)
130 {
131     napi_value result = nullptr;
132     napi_value eCode = nullptr;
133     NAPI_CALL(env, napi_create_int32(env, errCode, &eCode));
134     NAPI_CALL(env, napi_create_object(env, &result));
135     NAPI_CALL(env, napi_set_named_property(env, result, "code", eCode));
136     return result;
137 }
138 
SetPromise(const napi_env & env,const napi_deferred & deferred,const int & errorCode,const napi_value & result)139 void SetPromise(const napi_env &env, const napi_deferred &deferred, const int &errorCode, const napi_value &result)
140 {
141     if (errorCode == NO_ERROR) {
142         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, deferred, result));
143         return;
144     }
145     NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, deferred, result));
146 }
147 
SetCallback(const napi_env & env,const napi_ref & callbackIn,const int & errorCode,const napi_value & result)148 void SetCallback(const napi_env &env, const napi_ref &callbackIn, const int &errorCode, const napi_value &result)
149 {
150     napi_value undefined = nullptr;
151     napi_get_undefined(env, &undefined);
152 
153     napi_value callback = nullptr;
154     napi_value resultout = nullptr;
155     napi_get_reference_value(env, callbackIn, &callback);
156     napi_value results[ARGS_TWO] = {0};
157     results[PARAM0] = GetCallbackErrorValue(env, errorCode);
158     results[PARAM1] = result;
159     NAPI_CALL_RETURN_VOID(env, napi_call_function(env, undefined, callback, ARGS_TWO, &results[PARAM0], &resultout));
160 }
161 
JSParaError(const napi_env & env,const napi_ref & callback)162 napi_value JSParaError(const napi_env &env, const napi_ref &callback)
163 {
164     if (callback) {
165         return NapiGetNull(env);
166     } else {
167         napi_value promise = nullptr;
168         napi_deferred deferred = nullptr;
169         napi_create_promise(env, &deferred, &promise);
170         SetPromise(env, deferred, ERROR, NapiGetNull(env));
171         return promise;
172     }
173 }
174 
ReturnCallbackPromise(const napi_env & env,const CallbackPromiseInfo & info,const napi_value & result)175 void ReturnCallbackPromise(const napi_env &env, const CallbackPromiseInfo &info, const napi_value &result)
176 {
177     if (info.isCallback) {
178         SetCallback(env, info.callback, info.errorCode, result);
179     } else {
180         SetPromise(env, info.deferred, info.errorCode, result);
181     }
182 }
183 
ITimerInfoInstance()184 ITimerInfoInstance::ITimerInfoInstance()
185     : callbackInfo_ {}
186 {}
187 
~ITimerInfoInstance()188 ITimerInfoInstance::~ITimerInfoInstance()
189 {}
190 
OnTrigger()191 void ITimerInfoInstance::OnTrigger()
192 {
193     if (callbackInfo_.ref == nullptr) {
194         return;
195     }
196 
197     uv_loop_s *loop = nullptr;
198 #if NAPI_VERSION >= 2
199     napi_get_uv_event_loop(callbackInfo_.env, &loop);
200 #endif  // NAPI_VERSION >= 2
201 
202     ReceiveDataWorker *dataWorker = new (std::nothrow) ReceiveDataWorker();
203     if (!dataWorker) {
204         return;
205     }
206     dataWorker->env = callbackInfo_.env;
207     dataWorker->ref = callbackInfo_.ref;
208 
209     uv_work_t *work = new (std::nothrow) uv_work_t;
210     if (!work) {
211         delete dataWorker;
212         return;
213     }
214     if (!loop) {
215         delete dataWorker;
216         delete work;
217         return;
218     }
219     work->data = (void *)dataWorker;
220     uv_queue_work(loop,
221         work,
222         [](uv_work_t *work) {},
223         [](uv_work_t *work, int status) {
224             ReceiveDataWorker *dataWorkerData = (ReceiveDataWorker *)work->data;
225             if (dataWorkerData == nullptr) {
226                 return;
227             }
228             napi_handle_scope scope = nullptr;
229             napi_open_handle_scope(dataWorkerData->env, &scope);
230             if (scope == nullptr) {
231                 return;
232             }
233             SetCallback(dataWorkerData->env,
234                         dataWorkerData->ref,
235                         NO_ERROR,
236                         NapiGetNull(dataWorkerData->env));
237             napi_close_handle_scope(dataWorkerData->env, scope);
238             delete dataWorkerData;
239             dataWorkerData = nullptr;
240             delete work;
241             work = nullptr;
242         });
243 }
244 
SetCallbackInfo(const napi_env & env,const napi_ref & ref)245 void ITimerInfoInstance::SetCallbackInfo(const napi_env &env, const napi_ref &ref)
246 {
247     callbackInfo_.env = env;
248     callbackInfo_.ref = ref;
249 }
250 
SetType(const int & _type)251 void ITimerInfoInstance::SetType(const int &_type)
252 {
253     type = _type;
254 }
255 
SetRepeat(bool _repeat)256 void ITimerInfoInstance::SetRepeat(bool _repeat)
257 {
258     repeat = _repeat;
259 }
SetInterval(const uint64_t & _interval)260 void ITimerInfoInstance::SetInterval(const uint64_t &_interval)
261 {
262     interval = _interval;
263 }
SetWantAgent(std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent)264 void ITimerInfoInstance::SetWantAgent(std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent)
265 {
266     wantAgent = _wantAgent;
267 }
268 
GetTimerOptions(const napi_env & env,const napi_value & value,std::shared_ptr<ITimerInfoInstance> & iTimerInfoInstance)269 napi_value GetTimerOptions(const napi_env &env, const napi_value &value,
270     std::shared_ptr<ITimerInfoInstance> &iTimerInfoInstance)
271 {
272     napi_valuetype valuetype = napi_undefined;
273     napi_value result = nullptr;
274     OHOS::AbilityRuntime::WantAgent::WantAgent *wantAgent = nullptr;
275     bool hasProperty = false;
276 
277     // type: number
278     int type = 0;
279     NAPI_CALL(env, napi_has_named_property(env, value, "type", &hasProperty));
280     NAPI_ASSERT(env, hasProperty, "type expected.");
281     napi_get_named_property(env, value, "type", &result);
282     NAPI_CALL(env, napi_typeof(env, result, &valuetype));
283     NAPI_ASSERT(env, valuetype == napi_number, "Wrong argument type. Number expected.");
284     napi_get_value_int32(env, result, &type);
285     iTimerInfoInstance->SetType(type);
286 
287     // repeat: boolean
288     bool repeat = false;
289     NAPI_CALL(env, napi_has_named_property(env, value, "repeat", &hasProperty));
290     NAPI_ASSERT(env, hasProperty, "repeat expected.");
291     napi_get_named_property(env, value, "repeat", &result);
292     NAPI_CALL(env, napi_typeof(env, result, &valuetype));
293     NAPI_ASSERT(env, valuetype == napi_boolean, "Wrong argument type. Bool expected.");
294     napi_get_value_bool(env, result, &repeat);
295     iTimerInfoInstance->SetRepeat(repeat);
296 
297     // interval?: number
298     int64_t interval = 0;
299     NAPI_CALL(env, napi_has_named_property(env, value, "interval", &hasProperty));
300     if (hasProperty) {
301         napi_get_named_property(env, value, "interval", &result);
302         NAPI_CALL(env, napi_typeof(env, result, &valuetype));
303         NAPI_ASSERT(env, valuetype == napi_number, "Wrong argument type. Number expected.");
304         napi_get_value_int64(env, result, &interval);
305         NAPI_ASSERT(env, interval >= 0, "Wrong argument number. Positive number expected.");
306         iTimerInfoInstance->SetInterval((uint64_t)interval);
307     }
308 
309     // wantAgent?: WantAgent
310     NAPI_CALL(env, napi_has_named_property(env, value, "wantAgent", &hasProperty));
311     if (hasProperty) {
312         napi_get_named_property(env, value, "wantAgent", &result);
313         NAPI_CALL(env, napi_typeof(env, result, &valuetype));
314         NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type. Object expected.");
315         napi_unwrap(env, result, (void **)&wantAgent);
316         if (wantAgent == nullptr) {
317             return nullptr;
318         }
319         std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> sWantAgent =
320             std::make_shared<OHOS::AbilityRuntime::WantAgent::WantAgent>(*wantAgent);
321         iTimerInfoInstance->SetWantAgent(sWantAgent);
322     }
323 
324     // callback?: () => void
325     NAPI_CALL(env, napi_has_named_property(env, value, "callback", &hasProperty));
326     if (hasProperty) {
327         napi_get_named_property(env, value, "callback", &result);
328         NAPI_CALL(env, napi_typeof(env, result, &valuetype));
329         NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
330         napi_ref onTriggerCallback;
331         napi_create_reference(env, result, 1, &onTriggerCallback);
332         iTimerInfoInstance->SetCallbackInfo(env, onTriggerCallback);
333     }
334     return NapiGetNull(env);
335 }
336 
ParseParametersByCreateTimer(const napi_env & env,const napi_value (& argv)[CREATE_MAX_PARA],const size_t & argc,std::shared_ptr<ITimerInfoInstance> & iTimerInfoInstance,napi_ref & callback)337 napi_value ParseParametersByCreateTimer(const napi_env &env, const napi_value (&argv)[CREATE_MAX_PARA],
338     const size_t &argc, std::shared_ptr<ITimerInfoInstance> &iTimerInfoInstance, napi_ref &callback)
339 {
340     NAPI_ASSERT(env, argc >= CREATE_MAX_PARA - 1, "Wrong number of arguments");
341     napi_valuetype valuetype = napi_undefined;
342 
343     // argv[0]: TimerOptions
344     NAPI_CALL(env, napi_typeof(env, argv[0], &valuetype));
345     NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type. Object expected.");
346     if (GetTimerOptions(env, argv[0], iTimerInfoInstance) == nullptr) {
347         return nullptr;
348     }
349 
350     // argv[1]:callback
351     if (argc >= CREATE_MAX_PARA) {
352         NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype));
353         NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
354         napi_create_reference(env, argv[1], 1, &callback);
355     }
356 
357     return NapiGetNull(env);
358 }
359 
PaddingAsyncCallbackInfoIsByCreateTimer(const napi_env & env,AsyncCallbackInfoCreate * & asynccallbackinfo,const napi_ref & callback,napi_value & promise)360 void PaddingAsyncCallbackInfoIsByCreateTimer(
361     const napi_env &env, AsyncCallbackInfoCreate *&asynccallbackinfo, const napi_ref &callback, napi_value &promise)
362 {
363     if (callback) {
364         asynccallbackinfo->callback = callback;
365         asynccallbackinfo->isCallback = true;
366     } else {
367         napi_deferred deferred = nullptr;
368         NAPI_CALL_RETURN_VOID(env, napi_create_promise(env, &deferred, &promise));
369         asynccallbackinfo->deferred = deferred;
370         asynccallbackinfo->isCallback = false;
371     }
372 }
373 
CreateTimer(napi_env env,napi_callback_info info)374 napi_value CreateTimer(napi_env env, napi_callback_info info)
375 {
376     size_t argc = CREATE_MAX_PARA;
377     napi_value argv[CREATE_MAX_PARA] = {0};
378     napi_value thisVar = nullptr;
379     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
380     std::shared_ptr<ITimerInfoInstance> iTimerInfoInstance = std::make_shared<ITimerInfoInstance>();
381     napi_ref callback = nullptr;
382     if (ParseParametersByCreateTimer(env, argv, argc, iTimerInfoInstance, callback) == nullptr) {
383         return JSParaError(env, callback);
384     }
385     AsyncCallbackInfoCreate *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoCreate {
386         .env = env,
387         .asyncWork = nullptr,
388         .iTimerInfoInstance = iTimerInfoInstance
389     };
390     if (!asynccallbackinfo) {
391         return JSParaError(env, callback);
392     }
393     napi_value promise = nullptr;
394     PaddingAsyncCallbackInfoIsByCreateTimer(env, asynccallbackinfo, callback, promise);
395     napi_value resourceName = nullptr;
396     napi_create_string_latin1(env, "createTimer", NAPI_AUTO_LENGTH, &resourceName);
397     napi_create_async_work(env,
398         nullptr,
399         resourceName,
400         [](napi_env env, void *data) {
401             AsyncCallbackInfoCreate *asynccallbackinfo = (AsyncCallbackInfoCreate *)data;
402             asynccallbackinfo->timerId =
403                 TimeServiceClient::GetInstance()->CreateTimer(asynccallbackinfo->iTimerInfoInstance);
404             if (asynccallbackinfo->timerId > 0) {
405                 asyncCallbackInfoCreateInfo.emplace_back(asynccallbackinfo);
406             }
407         },
408         [](napi_env env, napi_status status, void *data) {
409             AsyncCallbackInfoCreate *asynccallbackinfo = (AsyncCallbackInfoCreate *)data;
410             CallbackPromiseInfo info;
411             info.isCallback = asynccallbackinfo->isCallback;
412             info.callback = asynccallbackinfo->callback;
413             info.deferred = asynccallbackinfo->deferred;
414             info.errorCode = asynccallbackinfo->errorCode;
415             napi_value result = nullptr;
416             napi_create_int64(env, asynccallbackinfo->timerId, &result);
417             ReturnCallbackPromise(env, info, result);
418             napi_delete_async_work(env, asynccallbackinfo->asyncWork);
419             if (asynccallbackinfo) {
420                 delete asynccallbackinfo;
421                 asynccallbackinfo = nullptr;
422             }
423         },
424         (void *)asynccallbackinfo,
425         &asynccallbackinfo->asyncWork);
426     NAPI_CALL(env, napi_queue_async_work(env, asynccallbackinfo->asyncWork));
427     if (asynccallbackinfo->isCallback) {
428         return NapiGetNull(env);
429     } else {
430         return promise;
431     }
432 }
433 
ParseParametersByStartTimer(const napi_env & env,const napi_value (& argv)[START_MAX_PARA],const size_t & argc,uint64_t & uintTimerId,uint64_t & uintTriggerTime,napi_ref & callback)434 napi_value ParseParametersByStartTimer(const napi_env &env, const napi_value (&argv)[START_MAX_PARA],
435     const size_t &argc, uint64_t &uintTimerId, uint64_t &uintTriggerTime, napi_ref &callback)
436 {
437     NAPI_ASSERT(env, argc >= START_MAX_PARA - 1, "Wrong number of arguments");
438     napi_valuetype valuetype = napi_undefined;
439 
440     // argv[0]: timer
441     NAPI_CALL(env, napi_typeof(env, argv[0], &valuetype));
442     NAPI_ASSERT(env, valuetype == napi_number, "Wrong argument type. Number expected.");
443     int64_t timerId = 0;
444     napi_get_value_int64(env, argv[0], &timerId);
445     NAPI_ASSERT(env, timerId >= 0, "Wrong argument timer. Positive number expected.");
446     uintTimerId = static_cast<uint64_t>(timerId);
447 
448     // argv[1]: triggerTime
449     NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype));
450     NAPI_ASSERT(env, valuetype == napi_number, "Wrong argument type. Number expected.");
451     int64_t triggerTime = 0;
452     napi_get_value_int64(env, argv[1], &triggerTime);
453     NAPI_ASSERT(env, triggerTime >= 0, "Wrong argument triggerTime. Positive number expected.");
454     uintTriggerTime = static_cast<uint64_t>(triggerTime);
455 
456     // argv[2]:callback
457     if (argc >= START_MAX_PARA) {
458         NAPI_CALL(env, napi_typeof(env, argv[TWO_PARAMETERS], &valuetype));
459         NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
460         napi_create_reference(env, argv[TWO_PARAMETERS], 1, &callback);
461     }
462 
463     return NapiGetNull(env);
464 }
465 
PaddingAsyncCallbackInfoIsByStartTimer(const napi_env & env,AsyncCallbackInfoStart * & asynccallbackinfo,const napi_ref & callback,napi_value & promise)466 void PaddingAsyncCallbackInfoIsByStartTimer(const napi_env &env,
467     AsyncCallbackInfoStart *&asynccallbackinfo,
468     const napi_ref &callback,
469     napi_value &promise)
470 {
471     if (callback) {
472         asynccallbackinfo->callback = callback;
473         asynccallbackinfo->isCallback = true;
474     } else {
475         napi_deferred deferred = nullptr;
476         NAPI_CALL_RETURN_VOID(env, napi_create_promise(env, &deferred, &promise));
477         asynccallbackinfo->deferred = deferred;
478         asynccallbackinfo->isCallback = false;
479     }
480 }
481 
StartTimer(napi_env env,napi_callback_info info)482 napi_value StartTimer(napi_env env, napi_callback_info info)
483 {
484     size_t argc = START_MAX_PARA;
485     napi_value argv[START_MAX_PARA] = {0};
486     napi_value thisVar = nullptr;
487     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
488 
489     uint64_t timerId;
490     uint64_t triggerTime;
491     napi_ref callback = nullptr;
492     if (ParseParametersByStartTimer(env, argv, argc, timerId, triggerTime, callback) == nullptr) {
493         return JSParaError(env, callback);
494     }
495 
496     AsyncCallbackInfoStart *asynccallbackinfo = new (std::nothrow)AsyncCallbackInfoStart {
497         .env = env,
498         .asyncWork = nullptr,
499         .timerId = timerId,
500         .triggerTime = triggerTime
501         };
502     if (!asynccallbackinfo) {
503         return JSParaError(env, callback);
504     }
505 
506     napi_value promise = nullptr;
507     PaddingAsyncCallbackInfoIsByStartTimer(env, asynccallbackinfo, callback, promise);
508 
509     napi_value resourceName = nullptr;
510     napi_create_string_latin1(env, "startTimer", NAPI_AUTO_LENGTH, &resourceName);
511     // Asynchronous function call
512     napi_create_async_work(env,
513         nullptr,
514         resourceName,
515         [](napi_env env, void *data) {
516             AsyncCallbackInfoStart *asynccallbackinfo = (AsyncCallbackInfoStart *)data;
517 
518             asynccallbackinfo->isOK = TimeServiceClient::GetInstance()->StartTimer(
519                 asynccallbackinfo->timerId, asynccallbackinfo->triggerTime);
520         },
521         [](napi_env env, napi_status status, void *data) {
522             AsyncCallbackInfoStart *asynccallbackinfo = (AsyncCallbackInfoStart *)data;
523 
524             if (!asynccallbackinfo->isOK) {
525                 asynccallbackinfo->errorCode = ERROR;
526             }
527             CallbackPromiseInfo info;
528             info.isCallback = asynccallbackinfo->isCallback;
529             info.callback = asynccallbackinfo->callback;
530             info.deferred = asynccallbackinfo->deferred;
531             info.errorCode = asynccallbackinfo->errorCode;
532 
533             // result: void
534             napi_value result = 0;
535             napi_get_null(env, &result);
536             ReturnCallbackPromise(env, info, result);
537 
538             napi_delete_async_work(env, asynccallbackinfo->asyncWork);
539             if (asynccallbackinfo) {
540                 delete asynccallbackinfo;
541                 asynccallbackinfo = nullptr;
542             }
543         },
544         (void *)asynccallbackinfo,
545         &asynccallbackinfo->asyncWork);
546 
547     NAPI_CALL(env, napi_queue_async_work(env, asynccallbackinfo->asyncWork));
548 
549     if (asynccallbackinfo->isCallback) {
550         return NapiGetNull(env);
551     } else {
552         return promise;
553     }
554 }
555 
ParseParametersByStopTimer(const napi_env & env,const napi_value (& argv)[STOP_MAX_PARA],const size_t & argc,uint64_t & uintTimerId,napi_ref & callback)556 napi_value ParseParametersByStopTimer(const napi_env &env, const napi_value (&argv)[STOP_MAX_PARA], const size_t &argc,
557     uint64_t &uintTimerId, napi_ref &callback)
558 {
559     NAPI_ASSERT(env, argc >= STOP_MAX_PARA - 1, "Wrong number of arguments");
560     napi_valuetype valuetype = napi_undefined;
561 
562     // argv[0]: timer
563     NAPI_CALL(env, napi_typeof(env, argv[0], &valuetype));
564     NAPI_ASSERT(env, valuetype == napi_number, "Wrong argument type. Number expected.");
565     int64_t timerId = 0;
566     napi_get_value_int64(env, argv[0], &timerId);
567     NAPI_ASSERT(env, timerId >= 0, "Wrong argument timer. Positive number expected.");
568     uintTimerId = static_cast<uint64_t>(timerId);
569 
570     // argv[1]:callback
571     if (argc >= STOP_MAX_PARA) {
572         NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype));
573         NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
574         napi_create_reference(env, argv[1], 1, &callback);
575     }
576 
577     return NapiGetNull(env);
578 }
579 
PaddingAsyncCallbackInfoIsByStopTimer(const napi_env & env,AsyncCallbackInfoStop * & asynccallbackinfo,const napi_ref & callback,napi_value & promise)580 void PaddingAsyncCallbackInfoIsByStopTimer(const napi_env &env,
581     AsyncCallbackInfoStop *&asynccallbackinfo,
582     const napi_ref &callback,
583     napi_value &promise)
584 {
585     if (callback) {
586         asynccallbackinfo->callback = callback;
587         asynccallbackinfo->isCallback = true;
588     } else {
589         napi_deferred deferred = nullptr;
590         NAPI_CALL_RETURN_VOID(env, napi_create_promise(env, &deferred, &promise));
591         asynccallbackinfo->deferred = deferred;
592         asynccallbackinfo->isCallback = false;
593     }
594 }
595 
StopTimer(napi_env env,napi_callback_info info)596 napi_value StopTimer(napi_env env, napi_callback_info info)
597 {
598     size_t argc = STOP_MAX_PARA;
599     napi_value argv[STOP_MAX_PARA] = {0};
600     napi_value thisVar = nullptr;
601     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
602 
603     uint64_t timerId;
604     napi_ref callback = nullptr;
605     if (ParseParametersByStopTimer(env, argv, argc, timerId, callback) == nullptr) {
606         return JSParaError(env, callback);
607     }
608 
609     AsyncCallbackInfoStop *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoStop {
610         .env = env,
611         .asyncWork = nullptr,
612         .timerId = timerId
613         };
614     if (!asynccallbackinfo) {
615         return JSParaError(env, callback);
616     }
617 
618     napi_value promise = nullptr;
619     PaddingAsyncCallbackInfoIsByStopTimer(env, asynccallbackinfo, callback, promise);
620 
621     napi_value resourceName = nullptr;
622     napi_create_string_latin1(env, "stopTimer", NAPI_AUTO_LENGTH, &resourceName);
623     // Asynchronous function call
624     napi_create_async_work(env,
625         nullptr,
626         resourceName,
627         [](napi_env env, void *data) {
628             AsyncCallbackInfoStop *asynccallbackinfo = (AsyncCallbackInfoStop *)data;
629             asynccallbackinfo->isOK = TimeServiceClient::GetInstance()->StopTimer(asynccallbackinfo->timerId);
630         },
631         [](napi_env env, napi_status status, void *data) {
632             AsyncCallbackInfoStop *asynccallbackinfo = (AsyncCallbackInfoStop *)data;
633 
634             if (!asynccallbackinfo->isOK) {
635                 asynccallbackinfo->errorCode = ERROR;
636             }
637             CallbackPromiseInfo info;
638             info.isCallback = asynccallbackinfo->isCallback;
639             info.callback = asynccallbackinfo->callback;
640             info.deferred = asynccallbackinfo->deferred;
641             info.errorCode = asynccallbackinfo->errorCode;
642 
643             // result: void
644             napi_value result = 0;
645             napi_get_null(env, &result);
646             ReturnCallbackPromise(env, info, result);
647 
648             napi_delete_async_work(env, asynccallbackinfo->asyncWork);
649             if (asynccallbackinfo) {
650                 delete asynccallbackinfo;
651                 asynccallbackinfo = nullptr;
652             }
653         },
654         (void *)asynccallbackinfo,
655         &asynccallbackinfo->asyncWork);
656 
657     NAPI_CALL(env, napi_queue_async_work(env, asynccallbackinfo->asyncWork));
658 
659     if (asynccallbackinfo->isCallback) {
660         return NapiGetNull(env);
661     } else {
662         return promise;
663     }
664 }
665 
ParseParametersByDestroyTimer(const napi_env & env,const napi_value (& argv)[DESTROY_MAX_PARA],const size_t & argc,uint64_t & uintTimerId,napi_ref & callback)666 napi_value ParseParametersByDestroyTimer(const napi_env &env, const napi_value (&argv)[DESTROY_MAX_PARA],
667     const size_t &argc, uint64_t &uintTimerId, napi_ref &callback)
668 {
669     NAPI_ASSERT(env, argc >= DESTROY_MAX_PARA - 1, "Wrong number of arguments");
670     napi_valuetype valuetype = napi_undefined;
671 
672     // argv[0]: timer
673     NAPI_CALL(env, napi_typeof(env, argv[0], &valuetype));
674     NAPI_ASSERT(env, valuetype == napi_number, "Wrong argument type. Number expected.");
675     int64_t timerId = 0;
676     napi_get_value_int64(env, argv[0], &timerId);
677     NAPI_ASSERT(env, timerId >= 0, "Wrong argument timer. Positive number expected.");
678     uintTimerId = (uint64_t)timerId;
679 
680     // argv[1]:callback
681     if (argc >= DESTROY_MAX_PARA) {
682         NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype));
683         NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
684         napi_create_reference(env, argv[1], 1, &callback);
685     }
686 
687     return NapiGetNull(env);
688 }
689 
PaddingAsyncCallbackInfoIsByDestroyTimer(const napi_env & env,AsyncCallbackInfoDestroy * & asynccallbackinfo,const napi_ref & callback,napi_value & promise)690 void PaddingAsyncCallbackInfoIsByDestroyTimer(
691     const napi_env &env, AsyncCallbackInfoDestroy *&asynccallbackinfo, const napi_ref &callback, napi_value &promise)
692 {
693     if (callback) {
694         asynccallbackinfo->callback = callback;
695         asynccallbackinfo->isCallback = true;
696     } else {
697         napi_deferred deferred = nullptr;
698         NAPI_CALL_RETURN_VOID(env, napi_create_promise(env, &deferred, &promise));
699         asynccallbackinfo->deferred = deferred;
700         asynccallbackinfo->isCallback = false;
701     }
702 }
703 
DestroyTimer(napi_env env,napi_callback_info info)704 napi_value DestroyTimer(napi_env env, napi_callback_info info)
705 {
706     size_t argc = DESTROY_MAX_PARA;
707     napi_value argv[DESTROY_MAX_PARA] = {0};
708     napi_value thisVar = nullptr;
709     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
710 
711     uint64_t timerId;
712     napi_ref callback = nullptr;
713     if (ParseParametersByDestroyTimer(env, argv, argc, timerId, callback) == nullptr) {
714         return JSParaError(env, callback);
715     }
716 
717     AsyncCallbackInfoDestroy *asynccallbackinfo =
718         new (std::nothrow) AsyncCallbackInfoDestroy {.env = env, .asyncWork = nullptr, .timerId = timerId};
719     if (!asynccallbackinfo) {
720         return JSParaError(env, callback);
721     }
722 
723     napi_value promise = nullptr;
724     PaddingAsyncCallbackInfoIsByDestroyTimer(env, asynccallbackinfo, callback, promise);
725 
726     napi_value resourceName = nullptr;
727     napi_create_string_latin1(env, "destroyTimer", NAPI_AUTO_LENGTH, &resourceName);
728     // Asynchronous function call
729     napi_create_async_work(env,
730         nullptr,
731         resourceName,
732         [](napi_env env, void *data) {
733             AsyncCallbackInfoDestroy *asynccallbackinfo = (AsyncCallbackInfoDestroy *)data;
734             asynccallbackinfo->isOK = TimeServiceClient::GetInstance()->DestroyTimer(asynccallbackinfo->timerId);
735         },
736         [](napi_env env, napi_status status, void *data) {
737             AsyncCallbackInfoDestroy *asynccallbackinfo = (AsyncCallbackInfoDestroy *)data;
738 
739             if (asynccallbackinfo->isOK) {
740                 for (auto it = asyncCallbackInfoCreateInfo.begin(); it != asyncCallbackInfoCreateInfo.end(); it++) {
741                     if ((*it)->timerId == asynccallbackinfo->timerId) {
742                         it = asyncCallbackInfoCreateInfo.erase(it);
743                         delete (*it);
744                         *it = nullptr;
745                     }
746                 }
747             } else {
748                 asynccallbackinfo->errorCode = ERROR;
749             }
750             CallbackPromiseInfo info;
751             info.isCallback = asynccallbackinfo->isCallback;
752             info.callback = asynccallbackinfo->callback;
753             info.deferred = asynccallbackinfo->deferred;
754             info.errorCode = asynccallbackinfo->errorCode;
755 
756             // result: void
757             napi_value result = 0;
758             napi_get_null(env, &result);
759             ReturnCallbackPromise(env, info, result);
760 
761             napi_delete_async_work(env, asynccallbackinfo->asyncWork);
762             if (asynccallbackinfo) {
763                 delete asynccallbackinfo;
764                 asynccallbackinfo = nullptr;
765             }
766         },
767         (void *)asynccallbackinfo,
768         &asynccallbackinfo->asyncWork);
769 
770     NAPI_CALL(env, napi_queue_async_work(env, asynccallbackinfo->asyncWork));
771 
772     if (asynccallbackinfo->isCallback) {
773         return NapiGetNull(env);
774     } else {
775         return promise;
776     }
777 }
778 
CreateNapiNumber(napi_env env,int32_t objName)779 napi_value CreateNapiNumber(napi_env env, int32_t objName)
780 {
781     napi_value prop = nullptr;
782     napi_create_int32(env, objName, &prop);
783     return prop;
784 }
785 
SystemtimerInit(napi_env env,napi_value exports)786 napi_value SystemtimerInit(napi_env env, napi_value exports)
787 {
788     napi_property_descriptor desc[] = {
789         DECLARE_NAPI_FUNCTION("createTimer", CreateTimer),
790         DECLARE_NAPI_FUNCTION("startTimer", StartTimer),
791         DECLARE_NAPI_FUNCTION("stopTimer", StopTimer),
792         DECLARE_NAPI_FUNCTION("destroyTimer", DestroyTimer),
793         DECLARE_NAPI_PROPERTY("TIMER_TYPE_REALTIME", CreateNapiNumber(env, 1 << TIMER_TYPE_REALTIME)),
794         DECLARE_NAPI_PROPERTY("TIMER_TYPE_WAKEUP", CreateNapiNumber(env, 1 << TIMER_TYPE_WAKEUP)),
795         DECLARE_NAPI_PROPERTY("TIMER_TYPE_EXACT", CreateNapiNumber(env, 1 << TIMER_TYPE_EXACT)),
796         DECLARE_NAPI_PROPERTY("TIMER_TYPE_IDLE", CreateNapiNumber(env, 1 << TIMER_TYPE_IDLE)),
797     };
798 
799     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
800     return exports;
801 }
802 }  // namespace MiscServicesNapi
803 }  // namespace OHOS