1/*
2 * Copyright (c) 2024 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 <mutex>
17#include <unordered_set>
18#include <map>
19#include <memory>
20
21#include "emitter_log.h"
22#include "inner_event.h"
23#include "event_handler_impl.h"
24#include "cj_fn_invoker.h"
25#include "emitter.h"
26
27using InnerEvent = OHOS::AppExecFwk::InnerEvent;
28using Priority = OHOS::AppExecFwk::EventQueue::Priority;
29
30namespace OHOS::EventsEmitter {
31    const int32_t SUCCESS = 0;
32    struct EventDataWorker {
33        CEventData data;
34        InnerEvent::EventId eventId;
35        CallbackInfo* callbackInfo;
36    };
37
38    static std::mutex g_emitterInsMutex;
39    static std::map<InnerEvent::EventId, std::unordered_set<CallbackInfo *>> g_emitterImpls;
40    std::shared_ptr<EventHandlerImpl> eventHandler = EventHandlerImpl::GetEventHandler();
41
42    CallbackImpl::CallbackImpl(std::string name, std::function<void(CEventData)> callback)
43        : name(name), callback(callback)
44    {}
45
46    CallbackInfo::~CallbackInfo()
47    {
48        callbackImpl = nullptr;
49    }
50
51    bool IsExistValidCallback(const InnerEvent::EventId &eventId)
52    {
53        std::lock_guard<std::mutex> lock(g_emitterInsMutex);
54        auto subscribe = g_emitterImpls.find(eventId);
55        if (subscribe == g_emitterImpls.end()) {
56            LOGW("emit has no callback");
57            return false;
58        }
59        for (auto callbackInfo : subscribe->second) {
60            if (!callbackInfo->isDeleted) {
61                return true;
62            }
63        }
64        return false;
65    }
66
67    void EmitWithEventData(InnerEvent::EventId eventId, uint32_t priority, CEventData data)
68    {
69        if (!IsExistValidCallback(eventId)) {
70            LOGE("Invalid callback");
71            return;
72        }
73        std::unique_ptr<CEventData> dataPtr;
74        if (data.size == 0) {
75            dataPtr = std::make_unique<CEventData>();
76        } else {
77            dataPtr = std::make_unique<CEventData>(data);
78        }
79        auto event = InnerEvent::Get(eventId, dataPtr);
80        eventHandler->SendEvent(event, 0, static_cast<Priority>(priority));
81    }
82
83    CallbackInfo *SearchCallbackInfo(const InnerEvent::EventId &eventIdValue, const std::string &callbackName)
84    {
85        auto subscribe = g_emitterImpls.find(eventIdValue);
86        if (subscribe == g_emitterImpls.end()) {
87            return nullptr;
88        }
89        for (auto callbackInfo : subscribe->second) {
90            if (callbackInfo->isDeleted) {
91                continue;
92            }
93            if (callbackInfo->callbackImpl->name == callbackName) {
94                LOGD("Callback found.")
95                return callbackInfo;
96            }
97        }
98        LOGD("Callback not found.")
99        return nullptr;
100    }
101
102    void UpdateOnceFlag(CallbackInfo *callbackInfo, bool once)
103    {
104        if (!once) {
105            if (callbackInfo->once) {
106                LOGD("On change once to on");
107                callbackInfo->once = false;
108            } else {
109                LOGD("On already on");
110            }
111        } else {
112            if (callbackInfo->once) {
113                LOGD("Once already once");
114            } else {
115                LOGD("Once change on to once");
116                callbackInfo->once = true;
117            }
118        }
119    }
120
121    void OutPutEventIdLog(const InnerEvent::EventId &eventId)
122    {
123        if (eventId.index() == OHOS::AppExecFwk::TYPE_U32_INDEX) {
124            LOGD("Event id value: %{public}u", std::get<uint32_t>(eventId));
125        } else {
126            LOGD("Event id value: %{public}s", std::get<std::string>(eventId).c_str());
127        }
128    }
129
130    int32_t OnOrOnce(InnerEvent::EventId eventId, CallbackImpl **callbackImpl, bool once)
131    {
132        OutPutEventIdLog(eventId);
133        std::lock_guard<std::mutex> lock(g_emitterInsMutex);
134        auto callback = *callbackImpl;
135        auto callbackInfo = SearchCallbackInfo(eventId, callback->name);
136        if (callbackInfo != nullptr) {
137            UpdateOnceFlag(callbackInfo, once);
138            delete callback;
139            *callbackImpl = nullptr;
140            return SUCCESS;
141        }
142        callbackInfo = new (std::nothrow) CallbackInfo();
143        if (!callbackInfo) {
144            LOGE("new callbackInfo failed");
145            delete callback;
146            *callbackImpl = nullptr;
147            return MEMORY_ERROR;
148        }
149        callbackInfo->callbackImpl = callback;
150        callbackInfo->once = once;
151        g_emitterImpls[eventId].insert(callbackInfo);
152        return SUCCESS;
153    }
154
155    int32_t Emitter::On(uint32_t eventId, CallbackImpl *callback)
156    {
157        InnerEvent::EventId id = eventId;
158        return OnOrOnce(id, &callback, false);
159    }
160
161    int32_t Emitter::On(char* eventId, CallbackImpl *callback)
162    {
163        InnerEvent::EventId id = std::string(eventId);
164        return OnOrOnce(id, &callback, false);
165    }
166
167    int32_t Emitter::Once(uint32_t eventId, CallbackImpl *callback)
168    {
169        InnerEvent::EventId id = eventId;
170        return OnOrOnce(id, &callback, true);
171    }
172
173    int32_t Emitter::Once(char* eventId, CallbackImpl *callback)
174    {
175        InnerEvent::EventId id = std::string(eventId);
176        return OnOrOnce(id, &callback, true);
177    }
178
179    void Unsubscribe(InnerEvent::EventId eventId)
180    {
181        std::lock_guard<std::mutex> lock(g_emitterInsMutex);
182        auto subscribe = g_emitterImpls.find(eventId);
183        if (subscribe != g_emitterImpls.end()) {
184            for (auto callbackInfo : subscribe->second) {
185                callbackInfo->isDeleted = true;
186            }
187        }
188    }
189
190    void Unsubscribe(InnerEvent::EventId eventId, CallbackImpl *callback)
191    {
192        std::lock_guard<std::mutex> lock(g_emitterInsMutex);
193        auto callbackInfo = SearchCallbackInfo(eventId, callback->name);
194        if (callbackInfo != nullptr) {
195            callbackInfo->isDeleted = true;
196        }
197    }
198
199    void Emitter::Off(uint32_t eventId)
200    {
201        InnerEvent::EventId id = eventId;
202        Unsubscribe(id);
203    }
204
205    void Emitter::Off(char* eventId)
206    {
207        InnerEvent::EventId id = std::string(eventId);
208        Unsubscribe(id);
209    }
210
211    void Emitter::Off(uint32_t eventId, CallbackImpl *callback)
212    {
213        InnerEvent::EventId id = eventId;
214        Unsubscribe(id, callback);
215    }
216
217    void Emitter::Off(char* eventId, CallbackImpl *callback)
218    {
219        InnerEvent::EventId id = std::string(eventId);
220        Unsubscribe(id, callback);
221    }
222
223    void Emitter::Emit(uint32_t eventId, uint32_t priority, CEventData data)
224    {
225        InnerEvent::EventId id = eventId;
226        EmitWithEventData(id, priority, data);
227    }
228
229    void Emitter::Emit(char* eventId, uint32_t priority, CEventData data)
230    {
231        InnerEvent::EventId id = std::string(eventId);
232        EmitWithEventData(id, priority, data);
233    }
234
235    uint32_t GetListenerCountByEventId(InnerEvent::EventId eventId)
236    {
237        uint32_t count = 0;
238        std::lock_guard<std::mutex> lock(g_emitterInsMutex);
239        auto subscribe = g_emitterImpls.find(eventId);
240        if (subscribe != g_emitterImpls.end()) {
241            for (auto callbackInfo : subscribe->second) {
242                if (!callbackInfo->isDeleted) {
243                    ++count;
244                }
245            }
246        }
247        return count;
248    }
249
250    uint32_t Emitter::GetListenerCount(uint32_t eventId)
251    {
252        InnerEvent::EventId id = eventId;
253        return GetListenerCountByEventId(id);
254    }
255
256    uint32_t Emitter::GetListenerCount(std::string eventId)
257    {
258        InnerEvent::EventId id = eventId;
259        return GetListenerCountByEventId(id);
260    }
261
262    void FreeCEventData(CEventData &eventData)
263    {
264        auto params = reinterpret_cast<CParameter *>(eventData.parameters);
265        for (int i = 0; i < eventData.size; i++) {
266            free(params[i].key);
267            free(params[i].value);
268            params[i].key = nullptr;
269            params[i].value = nullptr;
270        }
271        free(params);
272        params = nullptr;
273    }
274
275    void ProcessCallback(const InnerEvent::Pointer& event, std::unordered_set<CallbackInfo *>& callbackInfos)
276    {
277        auto value = event->GetUniqueObject<CEventData>();
278        CEventData eventData = { .parameters = nullptr, .size = 0};
279        if (value != nullptr) {
280            eventData = *value;
281        }
282        for (auto iter = callbackInfos.begin(); iter != callbackInfos.end();) {
283            CallbackInfo* callbackInfo = *iter;
284            if (callbackInfo->once || callbackInfo->isDeleted) {
285                LOGI("once callback or isDeleted callback");
286                iter = callbackInfos.erase(iter);
287                if (callbackInfo->processed) {
288                    delete callbackInfo->callbackImpl;
289                    delete callbackInfo;
290                    callbackInfo = nullptr;
291                    continue;
292                }
293            } else {
294                ++iter;
295            }
296            if (!callbackInfo->isDeleted) {
297                callbackInfo->callbackImpl->callback(eventData);
298            } else {
299                LOGD("callback is deleted.");
300            }
301            callbackInfo->processed = true;
302        }
303        FreeCEventData(eventData);
304    }
305
306    void EventHandlerImpl::ProcessEvent(const InnerEvent::Pointer& event)
307    {
308        LOGI("ProcessEvent");
309        InnerEvent::EventId eventId = event->GetInnerEventIdEx();
310        OutPutEventIdLog(eventId);
311        std::unordered_set<CallbackInfo *> callbackInfos;
312        {
313            std::lock_guard<std::mutex> lock(g_emitterInsMutex);
314            auto subscribe = g_emitterImpls.find(eventId);
315            if (subscribe == g_emitterImpls.end()) {
316                LOGW("ProcessEvent has no callback");
317                return;
318            }
319            callbackInfos = subscribe->second;
320        }
321        LOGD("size = %{public}zu", callbackInfos.size());
322        ProcessCallback(event, callbackInfos);
323        if (callbackInfos.empty()) {
324            g_emitterImpls.erase(eventId);
325            LOGD("ProcessEvent delete the last callback");
326        } else {
327            std::lock_guard<std::mutex> lock(g_emitterInsMutex);
328            auto subscribe = g_emitterImpls.find(eventId);
329            subscribe->second = callbackInfos;
330        }
331    }
332}