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 "event_target.h"
16
17 #include <cstring>
18
19 #include "securec.h"
20 #include "utils/log.h"
21
22 #define LISTENER_TYPTE_MAX_LENGTH 64
23
24 struct EventListener {
25 char type[LISTENER_TYPTE_MAX_LENGTH] = { 0 };
26 bool isOnce = false;
27 napi_ref handlerRef = nullptr;
28 EventListener* back = nullptr;
29 EventListener* next = nullptr;
30 };
31
EventTarget(napi_env env,napi_value thisVar)32 EventTarget::EventTarget(napi_env env, napi_value thisVar)
33 : env_(env), thisVarRef_(nullptr), first_(nullptr), last_(nullptr)
34 {
35 napi_create_reference(env, thisVar, 1, &thisVarRef_);
36 }
37
~EventTarget()38 EventTarget::~EventTarget()
39 {
40 EventListener* temp = nullptr;
41 for (EventListener* i = first_; i != nullptr; i = temp) {
42 temp = i->next;
43 if (i == first_) {
44 first_ = first_->next;
45 } else if (i == last_) {
46 last_ = last_->back;
47 } else {
48 i->next->back = i->back;
49 i->back->next = i->next;
50 }
51 napi_delete_reference(env_, i->handlerRef);
52 delete i;
53 }
54 napi_delete_reference(env_, thisVarRef_);
55 }
56
On(const char * type,napi_value handler)57 void EventTarget::On(const char* type, napi_value handler)
58 {
59 auto tmp = new EventListener();
60
61 if (strncpy_s(tmp->type, LISTENER_TYPTE_MAX_LENGTH, type, strlen(type)) != EOK) {
62 delete tmp;
63 tmp = nullptr;
64 return;
65 }
66
67 if (first_ == nullptr) {
68 first_ = last_ = tmp;
69 } else {
70 last_->next = tmp;
71 last_->next->back = last_;
72 last_ = last_->next;
73 }
74 last_->isOnce = false;
75 napi_create_reference(env_, handler, 1, &last_->handlerRef);
76 }
77
Once(const char * type,napi_value handler)78 void EventTarget::Once(const char* type, napi_value handler)
79 {
80 auto tmp = new EventListener();
81
82 if (strncpy_s(tmp->type, LISTENER_TYPTE_MAX_LENGTH, type, strlen(type)) != EOK) {
83 delete tmp;
84 tmp = nullptr;
85 return;
86 }
87
88 if (first_ == nullptr) {
89 first_ = last_ = tmp;
90 } else {
91 last_->next = tmp;
92 last_->next->back = last_;
93 last_ = last_->next;
94 }
95 last_->isOnce = true;
96 napi_create_reference(env_, handler, 1, &last_->handlerRef);
97 }
98
Off(const char * type,napi_value handler)99 void EventTarget::Off(const char* type, napi_value handler)
100 {
101 napi_handle_scope scope = nullptr;
102 napi_open_handle_scope(env_, &scope);
103 if (scope == nullptr) {
104 HILOG_ERROR("scope is nullptr");
105 return;
106 }
107
108 EventListener* temp = nullptr;
109 for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = temp) {
110 temp = eventListener->next;
111 bool isEquals = false;
112 napi_value handlerTemp = nullptr;
113 napi_get_reference_value(env_, eventListener->handlerRef, &handlerTemp);
114 napi_strict_equals(env_, handlerTemp, handler, &isEquals);
115 if (strcmp(eventListener->type, type) == 0 && isEquals) {
116 if (eventListener == first_) {
117 first_ = first_->next;
118 } else if (eventListener == last_) {
119 last_ = last_->back;
120 } else {
121 eventListener->next->back = eventListener->back;
122 eventListener->back->next = eventListener->next;
123 }
124 napi_delete_reference(env_, eventListener->handlerRef);
125 delete eventListener;
126 eventListener = nullptr;
127 break;
128 }
129 }
130 napi_close_handle_scope(env_, scope);
131 }
132
Off(const char * type)133 void EventTarget::Off(const char* type)
134 {
135 EventListener* temp = nullptr;
136 for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = temp) {
137 temp = eventListener->next;
138 if (strcmp(eventListener->type, type) == 0) {
139 if (eventListener == first_) {
140 first_ = first_->next;
141 } else if (eventListener == last_) {
142 last_ = last_->back;
143 } else {
144 eventListener->next->back = eventListener->back;
145 eventListener->back->next = eventListener->next;
146 }
147 napi_delete_reference(env_, eventListener->handlerRef);
148 delete eventListener;
149 eventListener = nullptr;
150 }
151 }
152 }
153
Emit(const char * type,Event * event)154 void EventTarget::Emit(const char* type, Event* event)
155 {
156 napi_handle_scope scope = nullptr;
157 napi_open_handle_scope(env_, &scope);
158
159 napi_value thisVar = nullptr;
160 napi_get_reference_value(env_, thisVarRef_, &thisVar);
161 for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = eventListener->next) {
162 if (strcmp(eventListener->type, type) == 0) {
163 napi_value jsEvent = event ? event->ToJsObject() : nullptr;
164 napi_value handler = nullptr;
165 napi_get_reference_value(env_, eventListener->handlerRef, &handler);
166 napi_call_function(env_, thisVar, handler, jsEvent ? 1 : 0, jsEvent ? &jsEvent : nullptr, nullptr);
167 if (eventListener->isOnce) {
168 Off(type, handler);
169 }
170 }
171 }
172
173 napi_close_handle_scope(env_, scope);
174 }
175