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 24struct 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 32EventTarget::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 38EventTarget::~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 57void 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 78void 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 99void 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 133void 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 154void 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