• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 "events_emitter.h"
17 
18 #include <iterator>
19 #include <memory>
20 #include <mutex>
21 #include <new>
22 #include <uv.h>
23 #include <unordered_set>
24 #include "event_logger.h"
25 #include "js_native_api_types.h"
26 #include "napi/native_node_api.h"
27 
28 using namespace std;
29 namespace OHOS {
30 namespace AppExecFwk {
31 namespace {
32     DEFINE_EH_HILOG_LABEL("EventsEmitter");
33     constexpr static uint32_t ARGC_ONE = 1u;
34 }
35     static std::mutex g_emitterInsMutex;
36     static map<InnerEvent::EventId, std::unordered_set<std::shared_ptr<AsyncCallbackInfo>>> emitterInstances;
37     std::shared_ptr<EventHandlerInstance> eventHandler;
~AsyncCallbackInfo()38     AsyncCallbackInfo::~AsyncCallbackInfo()
39     {
40         env = nullptr;
41     }
EventHandlerInstance(const std::shared_ptr<EventRunner> & runner)42     EventHandlerInstance::EventHandlerInstance(const std::shared_ptr<EventRunner>& runner): EventHandler(runner)
43     {
44         HILOGI("EventHandlerInstance constructed");
45     }
~EventHandlerInstance()46     EventHandlerInstance::~EventHandlerInstance()
47     {
48         HILOGI("EventHandlerInstance de-constructed");
49     }
GetInstance()50     std::shared_ptr<EventHandlerInstance> EventHandlerInstance::GetInstance()
51     {
52         static auto runner = EventRunner::Create("OS_eventsEmtr");
53         if (runner.get() == nullptr) {
54             HILOGE("failed to create EventRunner events_emitter");
55             return nullptr;
56         }
57         static auto instance = std::make_shared<EventHandlerInstance>(runner);
58         return instance;
59     }
60 
ProcessCallback(const EventDataWorker * eventDataInner)61     void ProcessCallback(const EventDataWorker* eventDataInner)
62     {
63         HILOGD("enter");
64 
65         std::shared_ptr<AsyncCallbackInfo> callbackInner = eventDataInner->callbackInfo;
66         napi_value resultData = nullptr;
67         if (eventDataInner->data != nullptr && *(eventDataInner->data) != nullptr) {
68             if (napi_deserialize(callbackInner->env, *(eventDataInner->data), &resultData) != napi_ok ||
69                 resultData == nullptr) {
70                 HILOGE("Deserialize fail.");
71                 return;
72             }
73         }
74         napi_value event = nullptr;
75         napi_create_object(callbackInner->env, &event);
76         napi_set_named_property(callbackInner->env, event, "data", resultData);
77         napi_value callback = nullptr;
78         napi_value returnVal = nullptr;
79         napi_get_reference_value(callbackInner->env, callbackInner->callback, &callback);
80         napi_call_function(callbackInner->env, nullptr, callback, 1, &event, &returnVal);
81         if (callbackInner->once) {
82             HILOGD("ProcessEvent delete once");
83             std::lock_guard<std::mutex> lock(g_emitterInsMutex);
84             auto iter = emitterInstances.find(callbackInner->eventId);
85             if (iter != emitterInstances.end()) {
86                 auto callback = iter->second.find(callbackInner);
87                 if (callback != iter->second.end()) {
88                     iter->second.erase(callback);
89                 }
90             }
91         }
92     }
93 
OutPutEventIdLog(const InnerEvent::EventId & eventId)94     void OutPutEventIdLog(const InnerEvent::EventId &eventId)
95     {
96         if (eventId.index() == TYPE_U32_INDEX) {
97             HILOGD("Event id value:%{public}u", std::get<uint32_t>(eventId));
98         } else {
99             HILOGD("Event id value:%{public}s", std::get<std::string>(eventId).c_str());
100         }
101     }
102 
ThreadSafeCallback(napi_env env,napi_value jsCallback,void * context,void * data)103     void ThreadSafeCallback(napi_env env, napi_value jsCallback, void* context, void* data)
104     {
105         napi_handle_scope scope;
106         EventDataWorker* eventDataInner = static_cast<EventDataWorker*>(data);
107         if (eventDataInner != nullptr) {
108             auto callbackInfoInner = eventDataInner->callbackInfo;
109             if (callbackInfoInner && !(callbackInfoInner->isDeleted)) {
110                 HILOGD("eventDataInner address: %{public}p", &eventDataInner);
111                 napi_open_handle_scope(callbackInfoInner->env, &scope);
112                 ProcessCallback(eventDataInner);
113                 napi_close_handle_scope(callbackInfoInner->env, scope);
114             }
115         }
116         delete eventDataInner;
117         eventDataInner = nullptr;
118         data = nullptr;
119     }
120 
ProcessEvent(const InnerEvent::Pointer & event)121     void EventHandlerInstance::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event)
122     {
123         InnerEvent::EventId eventId = event->GetInnerEventIdEx();
124         OutPutEventIdLog(eventId);
125         std::unordered_set<std::shared_ptr<AsyncCallbackInfo>> callbackInfos;
126         {
127             std::lock_guard<std::mutex> lock(g_emitterInsMutex);
128             auto iter = emitterInstances.find(eventId);
129             if (iter == emitterInstances.end()) {
130                 HILOGW("ProcessEvent has no callback");
131                 return;
132             }
133 
134             callbackInfos = iter->second;
135         }
136 
137         HILOGD("size = %{public}zu", callbackInfos.size());
138         auto value = event->GetUniqueObject<napi_value>();
139         std::shared_ptr<napi_value> eventData(value.release(), [this](napi_value* pData) {
140             if (pData != nullptr && (*pData) != nullptr && deleteEnv != nullptr) {
141                 napi_delete_serialization_data(deleteEnv, *pData);
142             }
143         });
144         for (auto it = callbackInfos.begin(); it != callbackInfos.end(); ++it) {
145             EventDataWorker* eventDataWorker = new (std::nothrow) EventDataWorker();
146             if (!eventDataWorker) {
147                 HILOGE("new object failed");
148                 continue;
149             }
150             deleteEnv = (*it)->env;
151             eventDataWorker->data = eventData;
152             eventDataWorker->callbackInfo = (*it);
153             napi_acquire_threadsafe_function((*it)->tsfn);
154             napi_call_threadsafe_function((*it)->tsfn, eventDataWorker, napi_tsfn_nonblocking);
155             napi_release_threadsafe_function((*it)->tsfn, napi_tsfn_release);
156         }
157     }
158 
UpdateOnceFlag(std::shared_ptr<AsyncCallbackInfo> callbackInfo,bool once)159     static void UpdateOnceFlag(std::shared_ptr<AsyncCallbackInfo>callbackInfo, bool once)
160     {
161         if (!once) {
162             if (callbackInfo->once) {
163                 HILOGD("JS_On change once to on");
164                 callbackInfo->once = false;
165             } else {
166                 HILOGD("JS_On already on");
167             }
168         } else {
169             if (callbackInfo->once) {
170                 HILOGD("JS_Once already once");
171             } else {
172                 HILOGD("JS_Once change on to once");
173                 callbackInfo->once = true;
174             }
175         }
176     }
177 
DeleteCallbackInfo(napi_env env,const InnerEvent::EventId & eventIdValue,napi_value argv)178     void DeleteCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv)
179     {
180         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
181         auto iter = emitterInstances.find(eventIdValue);
182         if (iter == emitterInstances.end()) {
183             return;
184         }
185         for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) {
186             napi_value callback = nullptr;
187             if ((*callbackInfo)->env != env) {
188                 ++callbackInfo;
189                 continue;
190             }
191             napi_get_reference_value((*callbackInfo)->env, (*callbackInfo)->callback, &callback);
192             bool isEq = false;
193             napi_strict_equals(env, argv, callback, &isEq);
194             if (!isEq) {
195                 ++callbackInfo;
196                 continue;
197             }
198             (*callbackInfo)->isDeleted = true;
199             callbackInfo = iter->second.erase(callbackInfo);
200             return;
201         }
202         return;
203     }
204 
SearchCallbackInfo(napi_env env,const InnerEvent::EventId & eventIdValue,napi_value argv)205     std::shared_ptr<AsyncCallbackInfo> SearchCallbackInfo(napi_env env, const InnerEvent::EventId &eventIdValue,
206         napi_value argv)
207     {
208         auto subscribe = emitterInstances.find(eventIdValue);
209         if (subscribe == emitterInstances.end()) {
210             return nullptr;
211         }
212         for (auto callbackInfo : subscribe->second) {
213             napi_value callback = nullptr;
214             if (callbackInfo->isDeleted) {
215                 continue;
216             }
217             if (callbackInfo->env != env) {
218                 continue;
219             }
220             napi_get_reference_value(callbackInfo->env, callbackInfo->callback, &callback);
221             bool isEq = false;
222             napi_strict_equals(env, argv, callback, &isEq);
223             if (!isEq) {
224                 continue;
225             }
226             return callbackInfo;
227         }
228         return nullptr;
229     }
230 
GetEventIdWithObjectOrString(napi_env env,napi_value argv,napi_valuetype eventValueType,InnerEvent::EventId & eventId)231     bool GetEventIdWithObjectOrString(
232         napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId)
233     {
234         if (eventValueType == napi_string) {
235             size_t valueStrBufLength = 0;
236             napi_get_value_string_utf8(env, argv, nullptr, NAPI_VALUE_STRING_LEN, &valueStrBufLength);
237             auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
238             size_t valueStrLength = 0;
239             napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
240             std::string id(valueCStr.get(), valueStrLength);
241             if (id.empty()) {
242                 HILOGE("Event id is empty for argument 1.");
243                 return false;
244             }
245             eventId = id;
246             HILOGD("Event id value:%{public}s", id.c_str());
247         } else {
248             bool hasEventId = false;
249             napi_has_named_property(env, argv, "eventId", &hasEventId);
250             if (!hasEventId) {
251                 HILOGE("Argument 1 does not have event id.");
252                 return false;
253             }
254 
255             napi_value eventIdValue = nullptr;
256             napi_get_named_property(env, argv, "eventId", &eventIdValue);
257             uint32_t id = 0u;
258             napi_get_value_uint32(env, eventIdValue, &id);
259             eventId = id;
260             HILOGD("Event id value:%{public}u", id);
261         }
262         return true;
263     }
264 
ThreadFinished(napi_env env,void * data,void * context)265     void ThreadFinished(napi_env env, void* data, [[maybe_unused]] void* context)
266     {
267         HILOGD("ThreadFinished");
268     }
269 
ReleaseCallbackInfo(AsyncCallbackInfo * callbackInfo)270     void ReleaseCallbackInfo(AsyncCallbackInfo* callbackInfo)
271     {
272         if (callbackInfo != nullptr) {
273             uv_loop_s *loop = nullptr;
274             if (napi_get_uv_event_loop(callbackInfo->env, &loop) != napi_ok) {
275                 return;
276             }
277             uv_work_t *work = new (std::nothrow) uv_work_t;
278             if (work == nullptr) {
279                 return;
280             }
281             work->data = reinterpret_cast<void*>(callbackInfo);
282             uv_queue_work_with_qos(loop, work, [](uv_work_t* work) {}, [](uv_work_t *work, int status) {
283                 AsyncCallbackInfo* callbackInfo = reinterpret_cast<AsyncCallbackInfo*>(work->data);
284                 if (napi_delete_reference(callbackInfo->env, callbackInfo->callback) != napi_ok) {
285                     HILOGE("napi_delete_reference fail.");
286                 }
287                 napi_release_threadsafe_function(callbackInfo->tsfn, napi_tsfn_release);
288                 delete callbackInfo;
289                 callbackInfo = nullptr;
290                 delete work;
291                 work = nullptr;
292             }, uv_qos_user_initiated);
293         }
294     }
295 
OnOrOnce(napi_env env,napi_callback_info cbinfo,bool once)296     napi_value OnOrOnce(napi_env env, napi_callback_info cbinfo, bool once)
297     {
298         size_t argc = ARGC_NUM;
299         napi_value argv[ARGC_NUM] = {0};
300         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
301         if (argc < ARGC_NUM) {
302             HILOGE("requires 2 parameter");
303             return nullptr;
304         }
305 
306         napi_valuetype eventValueType = GetNapiType(env, argv[0]);
307         if (eventValueType != napi_object && eventValueType != napi_string) {
308             HILOGE("type mismatch for parameter 1");
309             return nullptr;
310         }
311 
312         if (GetNapiType(env, argv[1]) != napi_function) {
313             HILOGE("type mismatch for parameter 2");
314             return nullptr;
315         }
316 
317         InnerEvent::EventId eventIdValue = 0u;
318         bool ret = GetEventIdWithObjectOrString(env, argv[0], eventValueType, eventIdValue);
319         if (!ret) {
320             return nullptr;
321         }
322         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
323         auto callbackInfo = SearchCallbackInfo(env, eventIdValue, argv[1]);
324         if (callbackInfo != nullptr) {
325             UpdateOnceFlag(callbackInfo, once);
326         } else {
327             callbackInfo = std::shared_ptr<AsyncCallbackInfo>(new (std::nothrow) AsyncCallbackInfo(),
328                 [](AsyncCallbackInfo* callbackInfo) {
329                 ReleaseCallbackInfo(callbackInfo);
330             });
331             if (!callbackInfo) {
332                 HILOGE("new object failed");
333                 return nullptr;
334             }
335             callbackInfo->env = env;
336             callbackInfo->once = once;
337             callbackInfo->eventId = eventIdValue;
338             napi_create_reference(env, argv[1], 1, &callbackInfo->callback);
339             napi_wrap(env, argv[1], new (std::nothrow) std::weak_ptr<AsyncCallbackInfo>(callbackInfo),
340                 [](napi_env env, void* data, void* hint) {
341                 auto callbackInfoPtr = static_cast<std::weak_ptr<AsyncCallbackInfo>*>(data);
342                 if (callbackInfoPtr != nullptr && (*callbackInfoPtr).lock() != nullptr) {
343                     (*callbackInfoPtr).lock()->isDeleted = true;
344                     (*callbackInfoPtr).lock()->env = nullptr;
345                 }
346             }, nullptr, nullptr);
347             napi_value resourceName = nullptr;
348             napi_create_string_utf8(env, "Call thread-safe function", NAPI_AUTO_LENGTH, &resourceName);
349             napi_create_threadsafe_function(env, argv[1], nullptr, resourceName, 0, 1, nullptr, ThreadFinished,
350                 nullptr, ThreadSafeCallback, &(callbackInfo->tsfn));
351             emitterInstances[eventIdValue].insert(callbackInfo);
352         }
353         return nullptr;
354     }
355 
GetEventIdWithNumberOrString(napi_env env,napi_value argv,napi_valuetype eventValueType,InnerEvent::EventId & eventId)356     bool GetEventIdWithNumberOrString(
357         napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId)
358     {
359         if (eventValueType == napi_string) {
360             size_t valueStrBufLength = 0;
361             napi_get_value_string_utf8(env, argv, nullptr, NAPI_VALUE_STRING_LEN, &valueStrBufLength);
362             auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
363             size_t valueStrLength = 0;
364             napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
365             std::string id(valueCStr.get(), valueStrLength);
366             if (id.empty()) {
367                 return false;
368             }
369             eventId = id;
370             HILOGD("Event id value:%{public}s", id.c_str());
371         } else {
372             uint32_t id = 0u;
373             napi_get_value_uint32(env, argv, &id);
374             eventId = id;
375             HILOGD("Event id value:%{public}u", id);
376         }
377         return true;
378     }
379 
JS_On(napi_env env,napi_callback_info cbinfo)380     napi_value JS_On(napi_env env, napi_callback_info cbinfo)
381     {
382         HILOGD("enter");
383         return OnOrOnce(env, cbinfo, false);
384     }
385 
JS_Once(napi_env env,napi_callback_info cbinfo)386     napi_value JS_Once(napi_env env, napi_callback_info cbinfo)
387     {
388         HILOGD("enter");
389         return OnOrOnce(env, cbinfo, true);
390     }
391 
JS_Off(napi_env env,napi_callback_info cbinfo)392     napi_value JS_Off(napi_env env, napi_callback_info cbinfo)
393     {
394         HILOGD("enter");
395         size_t argc = ARGC_NUM;
396         napi_value argv[ARGC_NUM] = {0};
397         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
398         if (argc < 1) {
399             HILOGE("requires at least 1 parameter");
400             return nullptr;
401         }
402 
403         napi_valuetype eventValueType;
404         napi_typeof(env, argv[0], &eventValueType);
405         if (eventValueType != napi_number && eventValueType != napi_string) {
406             HILOGE("type mismatch for parameter 1");
407             return nullptr;
408         }
409 
410         InnerEvent::EventId eventId = 0u;
411         bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId);
412         if (!ret) {
413             HILOGE("Event id is empty for parameter 1.");
414             return nullptr;
415         }
416 
417         if (argc == ARGC_NUM) {
418             napi_valuetype eventHandleType;
419             napi_typeof(env, argv[1], &eventHandleType);
420             if (eventHandleType != napi_function) {
421                 HILOGE("type mismatch for parameter 2");
422                 return nullptr;
423             }
424             DeleteCallbackInfo(env, eventId, argv[1]);
425             return nullptr;
426         }
427         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
428         auto iter = emitterInstances.find(eventId);
429         if (iter != emitterInstances.end()) {
430             for (auto callbackInfo : iter->second) {
431                 callbackInfo->isDeleted = true;
432             }
433         }
434         emitterInstances.erase(eventId);
435         return nullptr;
436     }
437 
EmitWithEventData(napi_env env,napi_value argv,const InnerEvent::EventId & eventId,Priority priority)438     bool EmitWithEventData(napi_env env, napi_value argv, const InnerEvent::EventId &eventId, Priority priority)
439     {
440         HILOGD("enter");
441         napi_valuetype dataType;
442         napi_typeof(env, argv, &dataType);
443         if (dataType != napi_object) {
444             HILOGE("type mismatch for parameter 2");
445             return false;
446         }
447         bool hasData = false;
448         napi_value serializeData = nullptr;
449         napi_has_named_property(env, argv, "data", &hasData);
450         if (hasData) {
451             napi_value data = nullptr;
452             napi_get_named_property(env, argv, "data", &data);
453             napi_status serializeResult = napi_ok;
454             napi_value undefined = nullptr;
455             napi_get_undefined(env, &undefined);
456             bool defaultTransfer = false;
457             bool defaultCloneSendable = true;
458             serializeResult = napi_serialize(env, data, undefined, undefined,
459                                              defaultTransfer, defaultCloneSendable, &serializeData);
460             if (serializeResult != napi_ok || serializeData == nullptr) {
461                 HILOGE("Serialize fail.");
462                 return false;
463             }
464         }
465         OutPutEventIdLog(eventId);
466         auto event = InnerEvent::Get(eventId, make_unique<napi_value>(serializeData));
467         eventHandler->SendEvent(event, 0, priority);
468         return true;
469     }
470 
IsExistValidCallback(napi_env env,const InnerEvent::EventId & eventId)471     bool IsExistValidCallback(napi_env env, const InnerEvent::EventId &eventId)
472     {
473         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
474         auto subscribe = emitterInstances.find(eventId);
475         if (subscribe == emitterInstances.end()) {
476             HILOGW("JS_Emit has no callback");
477             return false;
478         }
479         if (subscribe->second.size() != 0) {
480             return true;
481         }
482         return false;
483     }
484 
EmitWithEventIdUint32(napi_env env,size_t argc,napi_value argv[])485     napi_value EmitWithEventIdUint32(napi_env env, size_t argc, napi_value argv[])
486     {
487         InnerEvent::EventId eventId = 0u;
488         bool hasEventId = false;
489         napi_value value = nullptr;
490         napi_has_named_property(env, argv[0], "eventId", &hasEventId);
491         if (hasEventId == false) {
492             HILOGE("Wrong argument 1 does not have event id.");
493             return nullptr;
494         }
495 
496         napi_get_named_property(env, argv[0], "eventId", &value);
497         uint32_t id = 0u;
498         napi_get_value_uint32(env, value, &id);
499         eventId = id;
500         HILOGD("Event id value:%{public}u", id);
501 
502         if (!IsExistValidCallback(env, eventId)) {
503             HILOGE("Invalid callback");
504             return nullptr;
505         }
506 
507         bool hasPriority = false;
508         napi_has_named_property(env, argv[0], "priority", &hasPriority);
509         Priority priority = Priority::LOW;
510         if (hasPriority) {
511             napi_get_named_property(env, argv[0], "priority", &value);
512             uint32_t priorityValue = 0u;
513             napi_get_value_uint32(env, value, &priorityValue);
514             HILOGD("Event priority:%{public}d", priorityValue);
515             priority = static_cast<Priority>(priorityValue);
516         }
517 
518         if (argc == ARGC_NUM && EmitWithEventData(env, argv[1], eventId, priority)) {
519             return nullptr;
520         } else {
521             auto event = InnerEvent::Get(eventId, make_unique<EventData>());
522             eventHandler->SendEvent(event, 0, priority);
523         }
524         return nullptr;
525     }
526 
EmitWithEventIdString(napi_env env,size_t argc,napi_value argv[])527     napi_value EmitWithEventIdString(napi_env env, size_t argc, napi_value argv[])
528     {
529         InnerEvent::EventId eventId = 0u;
530         size_t valueStrBufLength = 0;
531         napi_get_value_string_utf8(env, argv[0], nullptr, NAPI_VALUE_STRING_LEN, &valueStrBufLength);
532         auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
533         size_t valueStrLength = 0;
534         napi_get_value_string_utf8(env, argv[0], valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
535         std::string id(valueCStr.get(), valueStrLength);
536         if (id.empty()) {
537             HILOGE("Invalid event id:%{public}s", id.c_str());
538             return nullptr;
539         }
540         eventId = id;
541         HILOGD("Event id value:%{public}s", id.c_str());
542 
543         if (!IsExistValidCallback(env, eventId)) {
544             HILOGE("Invalid callback");
545             return nullptr;
546         }
547 
548         Priority priority = Priority::LOW;
549         if (argc < ARGC_NUM) {
550             auto event = InnerEvent::Get(eventId, make_unique<EventData>());
551             eventHandler->SendEvent(event, 0, priority);
552             return nullptr;
553         }
554 
555         bool hasPriority = false;
556         napi_value value = nullptr;
557         napi_has_named_property(env, argv[1], "priority", &hasPriority);
558         if (!hasPriority) {
559             if (!EmitWithEventData(env, argv[1], eventId, priority)) {
560                 auto event = InnerEvent::Get(eventId, make_unique<EventData>());
561                 eventHandler->SendEvent(event, 0, priority);
562             }
563             return nullptr;
564         }
565 
566         napi_get_named_property(env, argv[1], "priority", &value);
567         uint32_t priorityValue = 0u;
568         napi_get_value_uint32(env, value, &priorityValue);
569         HILOGD("Event priority:%{public}d", priorityValue);
570         priority = static_cast<Priority>(priorityValue);
571 
572         if (argc > ARGC_NUM && EmitWithEventData(env, argv[ARGC_NUM], eventId, priority)) {
573             return nullptr;
574         } else {
575             auto event = InnerEvent::Get(eventId, make_unique<EventData>());
576             eventHandler->SendEvent(event, 0, priority);
577         }
578         return nullptr;
579     }
580 
JS_Emit(napi_env env,napi_callback_info cbinfo)581     napi_value JS_Emit(napi_env env, napi_callback_info cbinfo)
582     {
583         HILOGD("enter");
584         size_t argc = ARGC_NUM + ARGC_ONE;
585         napi_value argv[ARGC_NUM + ARGC_ONE] = {0};
586         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
587         if (argc < ARGC_ONE) {
588             HILOGE("Requires more than 1 parameter");
589             return nullptr;
590         }
591 
592         napi_valuetype eventValueType;
593         napi_typeof(env, argv[0], &eventValueType);
594         if (eventValueType != napi_object && eventValueType != napi_string) {
595             HILOGE("Type mismatch for parameter 1");
596             return nullptr;
597         }
598 
599         if (eventValueType == napi_string) {
600             return EmitWithEventIdString(env, argc, argv);
601         }
602         return EmitWithEventIdUint32(env, argc, argv);
603     }
604 
EnumEventClassConstructor(napi_env env,napi_callback_info info)605     napi_value EnumEventClassConstructor(napi_env env, napi_callback_info info)
606     {
607         napi_value thisArg = nullptr;
608         void *data = nullptr;
609 
610         napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
611 
612         napi_value global = nullptr;
613         napi_get_global(env, &global);
614 
615         return thisArg;
616     }
617 
CreateEnumEventPriority(napi_env env,napi_value exports)618     napi_value CreateEnumEventPriority(napi_env env, napi_value exports)
619     {
620         napi_value immediate = nullptr;
621         napi_value high = nullptr;
622         napi_value low = nullptr;
623         napi_value idle = nullptr;
624 
625         napi_create_uint32(env, (uint32_t)Priority::IMMEDIATE, &immediate);
626         napi_create_uint32(env, (uint32_t)Priority::HIGH, &high);
627         napi_create_uint32(env, (uint32_t)Priority::LOW, &low);
628         napi_create_uint32(env, (uint32_t)Priority::IDLE, &idle);
629 
630         napi_property_descriptor desc[] = {
631             DECLARE_NAPI_STATIC_PROPERTY("IMMEDIATE", immediate),
632             DECLARE_NAPI_STATIC_PROPERTY("HIGH", high),
633             DECLARE_NAPI_STATIC_PROPERTY("LOW", low),
634             DECLARE_NAPI_STATIC_PROPERTY("IDLE", idle),
635         };
636         napi_value result = nullptr;
637         napi_define_class(env, "EventPriority", NAPI_AUTO_LENGTH, EnumEventClassConstructor, nullptr,
638             sizeof(desc) / sizeof(*desc), desc, &result);
639 
640         napi_set_named_property(env, exports, "EventPriority", result);
641 
642         return exports;
643     }
644 
CreateJsUndefined(napi_env env)645     napi_value CreateJsUndefined(napi_env env)
646     {
647         napi_value result = nullptr;
648         napi_get_undefined(env, &result);
649         return result;
650     }
651 
CreateJsNumber(napi_env env,uint32_t value)652     napi_value CreateJsNumber(napi_env env, uint32_t value)
653     {
654         napi_value result = nullptr;
655         napi_create_uint32(env, value, &result);
656         return result;
657     }
658 
JS_GetListenerCount(napi_env env,napi_callback_info cbinfo)659     napi_value JS_GetListenerCount(napi_env env, napi_callback_info cbinfo)
660     {
661         HILOGD("enter");
662         size_t argc = ARGC_NUM;
663         napi_value argv[ARGC_NUM] = {0};
664         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
665         if (argc < ARGC_ONE) {
666             HILOGE("Requires more than 1 parameter");
667             return CreateJsUndefined(env);
668         }
669 
670         napi_valuetype eventValueType;
671         napi_typeof(env, argv[0], &eventValueType);
672         if (eventValueType != napi_number && eventValueType != napi_string) {
673             HILOGE("Type mismatch for parameter 1");
674             return CreateJsUndefined(env);
675         }
676 
677         uint32_t cnt = 0u;
678         InnerEvent::EventId eventId = 0u;
679         bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId);
680         if (!ret) {
681             HILOGE("Event id is empty for parameter 1.");
682             return CreateJsUndefined(env);
683         }
684         std::lock_guard<std::mutex> lock(g_emitterInsMutex);
685         auto subscribe = emitterInstances.find(eventId);
686         if (subscribe != emitterInstances.end()) {
687             for (auto callbackInfo : subscribe->second) {
688                 ++cnt;
689             }
690         }
691         return CreateJsNumber(env, cnt);
692     }
693 
EmitterInit(napi_env env,napi_value exports)694     napi_value EmitterInit(napi_env env, napi_value exports)
695     {
696         HILOGD("enter");
697         napi_property_descriptor desc[] = {
698             DECLARE_NAPI_FUNCTION("on", JS_On),
699             DECLARE_NAPI_FUNCTION("once", JS_Once),
700             DECLARE_NAPI_FUNCTION("off", JS_Off),
701             DECLARE_NAPI_FUNCTION("emit", JS_Emit),
702             DECLARE_NAPI_FUNCTION("getListenerCount", JS_GetListenerCount),
703         };
704         NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
705 
706         CreateEnumEventPriority(env, exports);
707 
708         eventHandler = EventHandlerInstance::GetInstance();
709         return exports;
710     }
711 }  // namespace AppExecFwk
712 }  // namespace OHOS
713