RTC Toolkit 5.1.0
Loading...
Searching...
No Matches
typedEventService.hpp
Go to the documentation of this file.
1
13#ifndef RTCTK_COMPONENTFRAMEWORK_TYPEDEVENTSERVICE_HPP
14#define RTCTK_COMPONENTFRAMEWORK_TYPEDEVENTSERVICE_HPP
15
19
20#include <map>
21#include <mutex>
22#include <set>
23#include <string>
24
26
27namespace detail {
28
29// internal helper class to keep track of publishers
34public:
35 explicit TypedEventPublisherManager(EventServiceIf& es) : m_es(es) {
36 }
37
38 template <typename EventType>
40 std::lock_guard guard(m_mutex);
41
42 const std::string tpc_name = EventType::TOPIC_NAME;
43
44 if (m_hl_publishers.count(tpc_name) == 0) {
45 m_hl_publishers[tpc_name] = 1;
46 m_ll_publishers[tpc_name] = m_es.MakePublisher(tpc_name);
47 } else {
48 m_hl_publishers[tpc_name] += 1;
49 }
50 }
51
52 template <typename EventType>
54 std::lock_guard guard(m_mutex);
55
56 const std::string tpc_name = EventType::TOPIC_NAME;
57
58 if (m_hl_publishers.count(tpc_name)) {
59 if (m_hl_publishers.at(tpc_name) >= 1) {
60 m_hl_publishers.at(tpc_name) -= 1;
61 }
62
63 if (m_hl_publishers.at(tpc_name) == 0) {
64 m_hl_publishers.erase(tpc_name);
65 m_ll_publishers.erase(tpc_name);
66 }
67 }
68 }
69
70 template <typename EventType>
71 void Publish(const EventType& sample) {
72 std::lock_guard guard(m_mutex);
73
74// we dont need any deprecation warnings in already deprecated code
75#pragma GCC diagnostic push
76#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
77 const std::string tpc_name = EventType::TOPIC_NAME;
78 m_ll_publishers.at(tpc_name)->Publish(sample.ToJson());
79#pragma GCC diagnostic pop
80 }
81
82private:
83 // handle to low-level event service
84 EventServiceIf& m_es;
85
86 // to synchronise access on the data structure
87 std::mutex m_mutex;
88
89 // to keep track of publishers
90 std::map<std::string, unsigned> m_hl_publishers;
91 std::map<std::string, std::unique_ptr<EventPublisherIf>> m_ll_publishers;
92};
93
94// internal helper class to keep track of subscribers
99public:
101 }
102
103 template <typename EventType>
105 std::lock_guard guard(m_mutex);
106
107 const std::string tpc_name = EventType::TOPIC_NAME;
108
109 if (m_hl_subscribers.count(tpc_name) == 0) {
110 m_hl_subscribers[tpc_name].insert(id);
111 m_ll_subscribers[tpc_name] = m_es.MakeSubscriber(tpc_name);
112 } else {
113 m_hl_subscribers[tpc_name].insert(id);
114 }
115 }
116
117 template <typename EventType>
119 std::lock_guard guard(m_mutex);
120
122
123 // delete subscriber
124 const std::string tpc_name = EventType::TOPIC_NAME;
125
126 if (m_hl_subscribers.count(tpc_name)) {
127 m_hl_subscribers.at(tpc_name).erase(id);
128
129 if (m_hl_subscribers.at(tpc_name).empty()) {
130 m_hl_subscribers.erase(tpc_name);
131 m_ll_subscribers.erase(tpc_name);
132 }
133 }
134 }
135
136 template <typename EventType>
137 void Subscribe(uintptr_t id, std::function<void(const EventType&)> cb) {
138 std::lock_guard guard(m_mutex);
139
140 const std::string tpc_name = EventType::TOPIC_NAME;
141 const std::string evt_type = PrettyTypeName<EventType>();
142
143 if (m_callbacks.count(tpc_name) == 0) {
144 m_ll_subscribers.at(tpc_name)->Subscribe([this, tpc_name](const JsonPayload& pl) {
145 std::lock_guard guard(m_mutex);
146
147 if (m_callbacks.count(tpc_name) != 0) {
148 for (const auto& [key, val] : m_callbacks.at(tpc_name)) {
149 for (const auto& [k, obj] : val) {
150 (*obj)(pl); // invoke the callback
151 }
152 }
153 }
154 });
155 }
156
157 m_callbacks[tpc_name][evt_type][id] = std::make_shared<FuncObj<EventType>>(cb);
158 }
159
160 template <typename EventType>
162 std::lock_guard guard(m_mutex);
163
165 }
166
167private:
168 template <typename EventType>
169 void UnsubscribePrivate(uintptr_t id) {
170 const std::string tpc_name = EventType::TOPIC_NAME;
171 const std::string evt_type = PrettyTypeName<EventType>();
172
173 if (m_callbacks.count(tpc_name) and m_callbacks.at(tpc_name).count(evt_type) and
174 m_callbacks.at(tpc_name).at(evt_type).count(id)) {
175 m_callbacks.at(tpc_name).at(evt_type).erase(id);
176 if (m_callbacks.at(tpc_name).at(evt_type).empty()) {
177 m_callbacks.at(tpc_name).erase(evt_type);
178 if (m_callbacks.at(tpc_name).empty()) {
179 m_callbacks.erase(tpc_name);
180 m_ll_subscribers.at(tpc_name)->Unsubscribe();
181 }
182 }
183 }
184 }
185
186 // Basic functor interface for book-keeping
187 class FuncObjBase {
188 public:
189 virtual ~FuncObjBase() = default;
190 virtual void operator()(const JsonPayload& sample) = 0;
191 };
192
193 // Specific functor classes that host event callbacks
194 template <typename EventType>
195 class FuncObj : public FuncObjBase {
196 public:
197 static_assert(std::is_base_of_v<AbstractEvent, EventType>,
198 "EventType must extend AbstractEvent");
199
200 explicit FuncObj(std::function<void(const EventType&)> cb) : m_cb(cb) {
201 }
202
203 void operator()(const JsonPayload& sample) override {
204 if (std::count(
205 sample["type"].begin(), sample["type"].end(), PrettyTypeName<EventType>())) {
206// we dont need any deprecation warnings in already deprecated code
207#pragma GCC diagnostic push
208#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
209 m_cb(EventType(sample));
210#pragma GCC diagnostic pop
211 }
212 }
213
214 private:
215 std::function<void(const EventType&)> m_cb;
216 };
217
218 // handle to low-level event service
219 EventServiceIf& m_es;
220
221 // to keep track of subscribers
222 std::map<std::string, std::set<uintptr_t>> m_hl_subscribers;
223 std::map<std::string, std::unique_ptr<EventSubscriberIf>> m_ll_subscribers;
224
225 // We keep track of our event type subscriptions in a map of maps of maps of function objects:
226 // - the first level map keys are the currently subscribed 'topic names'
227 // - the second level map keys are the currently subscribed 'event types' of a 'topic name'
228 // note that multiple 'event types' can share the same 'topic name'
229 // - the third level map keys are the ids of the subscriber instance
230 // note that multiple subscribers can subscribe to same 'topic name' and 'event type'
231 // - the final values are the function objects used to invoke the right callback
232 std::map<std::string, std::map<std::string, std::map<uintptr_t, std::shared_ptr<FuncObjBase>>>>
233 m_callbacks;
234
235 // used to synchronise access on the above data structure
236 std::mutex m_mutex;
237};
238
239} // namespace detail
240
241// forward declarations
242
243template <typename EventType>
244class TypedEventPublisher;
245
246template <typename EventType>
247class TypedEventSubscriber;
248
257class [[deprecated("Use EventServiceIf instead.")]] TypedEventService {
258public:
259 explicit TypedEventService(EventServiceIf& es) : m_pub_man(es), m_sub_man(es) {
260 }
261
267 template <typename EventType>
268 std::unique_ptr<TypedEventPublisher<EventType>> MakePublisher() {
269 return std::unique_ptr<TypedEventPublisher<EventType>>(
270 new TypedEventPublisher<EventType>(m_pub_man));
271 }
272
278 template <typename EventType>
279 std::unique_ptr<TypedEventSubscriber<EventType>> MakeSubscriber() {
280 return std::unique_ptr<TypedEventSubscriber<EventType>>(
281 new TypedEventSubscriber<EventType>(m_sub_man));
282 }
283
284private:
287};
288
299template <typename EventType>
300class [[deprecated("Use EventPublisherIf instead.")]] TypedEventPublisher {
301public:
302 // Use the factory method from the TypedEventService to construct publisher objects
304
306 m_man.UnregisterPublisher<EventType>();
307 }
308
316 void Publish(const EventType& sample) {
317 m_man.Publish(sample);
318 }
319
320private:
321 explicit TypedEventPublisher(detail::TypedEventPublisherManager& man) : m_man(man) {
322 man.RegisterPublisher<EventType>();
323 }
324
325 detail::TypedEventPublisherManager& m_man;
326};
327
338template <typename EventType>
339class [[deprecated("Use EventSubscriberIf instead.")]] TypedEventSubscriber {
340public:
341 // Use the factory method from the TypedEventService to construct subscriber objects
343
345 m_man.UnregisterSubscriber<EventType>(reinterpret_cast<uintptr_t>(this));
346 }
347
358 void Subscribe(std::function<void(const EventType&)> cb) {
359 m_man.Subscribe<EventType>(reinterpret_cast<uintptr_t>(this), cb);
360 }
361
367 void Unsubscribe() {
368 m_man.Unsubscribe<EventType>(reinterpret_cast<uintptr_t>(this));
369 }
370
371private:
373 m_man.RegisterSubscriber<EventType>(reinterpret_cast<uintptr_t>(this));
374 }
375
376 detail::TypedEventSubscriberManager& m_man;
377};
378
379} // namespace rtctk::componentFramework
380
381#endif // RTCTK_COMPONENTFRAMEWORK_TYPEDEVENTSERVICE_HPP
Interface class for providing pub/sub facilities for JSON events.
Definition eventServiceIf.hpp:29
virtual std::unique_ptr< EventSubscriberIf > MakeSubscriber(const std::string &topic)=0
Creates a new subscriber for a specified topic.
virtual std::unique_ptr< EventPublisherIf > MakePublisher(const std::string &topic)=0
Creates a new publisher for a specified topic.
An event publisher that is aware of event types.
Definition typedEventService.hpp:300
friend TypedEventService
Definition typedEventService.hpp:303
~TypedEventPublisher()
Definition typedEventService.hpp:305
void Publish(const EventType &sample)
Publishes an event of a specific type.
Definition typedEventService.hpp:316
A high-level event service API that is aware of event types.
Definition typedEventService.hpp:257
std::unique_ptr< TypedEventPublisher< EventType > > MakePublisher()
Creates a new publisher for a specified event type.
Definition typedEventService.hpp:268
TypedEventService(EventServiceIf &es)
Definition typedEventService.hpp:259
std::unique_ptr< TypedEventSubscriber< EventType > > MakeSubscriber()
Creates a new subscriber for a specified event type.
Definition typedEventService.hpp:279
An event subscriber that is aware of event types.
Definition typedEventService.hpp:339
~TypedEventSubscriber()
Definition typedEventService.hpp:344
friend TypedEventService
Definition typedEventService.hpp:342
void Unsubscribe()
Unsubscribes from a specified event type.
Definition typedEventService.hpp:367
void Subscribe(std::function< void(const EventType &)> cb)
Subscribes to an event of a specific type.
Definition typedEventService.hpp:358
void Publish(const EventType &sample)
Definition typedEventService.hpp:71
void UnregisterPublisher()
Definition typedEventService.hpp:53
TypedEventPublisherManager(EventServiceIf &es)
Definition typedEventService.hpp:35
void RegisterPublisher()
Definition typedEventService.hpp:39
void UnregisterSubscriber(uintptr_t id)
Definition typedEventService.hpp:118
void Unsubscribe(uintptr_t id)
Definition typedEventService.hpp:161
TypedEventSubscriberManager(EventServiceIf &es)
Definition typedEventService.hpp:100
void RegisterSubscriber(uintptr_t id)
Definition typedEventService.hpp:104
void Subscribe(uintptr_t id, std::function< void(const EventType &)> cb)
Definition typedEventService.hpp:137
Framework-provided event definitions.
Low-level interface of the event service.
Defines the JSON payload type JsonPayload.
Definition commandReplier.cpp:22
nlohmann::json JsonPayload
Type requirements:
Definition jsonPayload.hpp:25
elt::mal::future< std::string > InjectReqRepEvent(StateMachineEngine &engine)
Definition malEventInjector.hpp:23