libkazv
Loading...
Searching...
No Matches
lagerstoreeventemitter.hpp
Go to the documentation of this file.
1/*
2 * This file is part of libkazv.
3 * SPDX-FileCopyrightText: 2020-2026 tusooa <tusooa@kazv.moe>
4 * SPDX-License-Identifier: AGPL-3.0-or-later
5 */
6
7#pragma once
8#include <libkazv-config.hpp>
9
10#include <vector>
11#include <memory>
12#include <algorithm>
13
14
15#include <lager/store.hpp>
16#include <lager/reader.hpp>
17#include <lager/event_loop/manual.hpp>
18
19#include "types.hpp"
20
21#include "eventinterface.hpp"
22
23namespace Kazv
24{
26 {
27 struct Model { KazvTrigger curEvent; };
28 struct Action { KazvTrigger nextEvent; };
29
30 struct ListenerHolder;
31
32 using Result = std::pair<Model,
33 lager::effect<Action, lager::deps<ListenerHolder &>>>;
34
35 using SlotT = std::function<void(KazvTrigger)>;
36
37 struct Listener
38 {
39 void emit(KazvTrigger e) {
40 for (const auto &slot: m_slots) {
41 slot(e);
42 }
43 }
44
45 void connect(SlotT slot) {
46 m_slots.push_back(std::move(slot));
47 }
48
49 std::vector<SlotT> m_slots;
50 };
51
52 using ListenerSP = std::shared_ptr<Listener>;
53 using ListenerWSP = std::weak_ptr<Listener>;
54
55 struct ListenerHolder
56 {
57 void sendToListeners(KazvTrigger e) {
58 bool needsCleanup = false;
59 for (auto listener : m_listeners) {
60 auto strongListener = listener.lock();
61 if (strongListener) {
62 strongListener->emit(e);
63 } else {
64 needsCleanup = true;
65 }
66 }
67
68 if (needsCleanup) {
69 std::remove_if(m_listeners.begin(),
70 m_listeners.end(),
71 [](auto ptr) {
72 return ptr.expired();
73 });
74 }
75
76 }
77
78 std::vector<ListenerWSP> m_listeners;
79 };
80
81 inline static Result update(Model, Action a) {
82 return {
83 Model{a.nextEvent},
84 [=](auto &&ctx) {
85 auto &holder = lager::get<ListenerHolder &>(ctx);
86 holder.sendToListeners(a.nextEvent);
87 }
88 };
89 }
90
91 public:
92 template<class EventLoop>
93 LagerStoreEventEmitter(EventLoop loop)
94 : m_holder{}
95 , m_store(
96 lager::make_store<Action>(
97 Model{},
98 loop,
99 lager::with_reducer(&update),
100 lager::with_deps(std::ref(m_holder))))
101 , m_postingFunc(
102 [loop=loop](auto &&func) mutable {
103 loop.post(std::forward<decltype(func)>(func));
104 }) {}
105 ~LagerStoreEventEmitter() override = default;
106
107 void emit(KazvTrigger e) override {
108 m_store.dispatch(Action{e});
109 }
110
112 {
113 public:
115 : m_listener(std::make_shared<Listener>()) {
116 ee.addListener(m_listener);
117 }
118 template<class EventType, class Func>
119 void after(Func &&func) {
120 m_listener->connect(
121 [f=std::forward<Func>(func)](KazvTrigger e) {
122 if (std::holds_alternative<EventType>(e)) {
123 f(std::get<EventType>(e));
124 }
125 });
126 }
127
128 template<class Func>
129 void afterAll(Func &&func) {
130 m_listener->connect(
131 [f=std::forward<Func>(func)](KazvTrigger e) {
132 f(e);
133 });
134 }
135
136 private:
137 ListenerSP m_listener;
138 };
139
149 return Watchable(*this);
150 }
151
152
153 private:
154 void addListener(ListenerSP listener) {
155 m_postingFunc([=]() {
156 m_holder.m_listeners.push_back(listener);
157 });
158 }
159
160 using StoreT =
161 decltype(lager::make_store<Action>(
162 Model{},
163 lager::with_manual_event_loop{},
164 lager::with_reducer(&update),
165 lager::with_deps(std::ref(detail::declref<ListenerHolder>()))));
166
167 using PostingFunc = std::function<void(std::function<void()>)>;
168
169 ListenerHolder m_holder;
170 StoreT m_store;
171 PostingFunc m_postingFunc;
172 };
173
174}
Definition eventinterface.hpp:15
Definition lagerstoreeventemitter.hpp:112
void afterAll(Func &&func)
Definition lagerstoreeventemitter.hpp:129
Watchable(LagerStoreEventEmitter &ee)
Definition lagerstoreeventemitter.hpp:114
void after(Func &&func)
Definition lagerstoreeventemitter.hpp:119
Definition lagerstoreeventemitter.hpp:26
Watchable watchable()
An object you can watch for events.
Definition lagerstoreeventemitter.hpp:148
~LagerStoreEventEmitter() override=default
LagerStoreEventEmitter(EventLoop loop)
Definition lagerstoreeventemitter.hpp:93
void emit(KazvTrigger e) override
Definition lagerstoreeventemitter.hpp:107
Definition location.hpp:10
std::variant< std::monostate, ReceivingPresenceEvent, ReceivingAccountDataEvent, ReceivingRoomTimelineEvent, ReceivingRoomStateEvent, RoomMembershipChanged, ReceivingRoomAccountDataEvent, ReceivingToDeviceMessage, LoginSuccessful, LoginFailed, SaveEventsRequested, UnrecognizedResponse > KazvTrigger
Definition kazv-triggers.hpp:99
Definition clientutil.hpp:140