17#include <trantor/utils/NonCopyable.h>
20#include <shared_mutex>
23#include <unordered_map>
27using SubscriberID = uint64_t;
34template <
typename MessageType>
35class Topic :
public trantor::NonCopyable
38 using MessageHandler = std::function<void(
const MessageType &)>;
39#if __cplusplus >= 201703L | defined _WIN32
40 using SharedMutex = std::shared_mutex;
42 using SharedMutex = std::shared_timed_mutex;
50 void publish(
const MessageType &message)
const
52 std::shared_lock<SharedMutex> lock(mutex_);
53 for (
auto &pair : handlersMap_)
65 SubscriberID
subscribe(
const MessageHandler &handler)
67 std::unique_lock<SharedMutex> lock(mutex_);
68 handlersMap_[++id_] = handler;
80 std::unique_lock<SharedMutex> lock(mutex_);
81 handlersMap_[++id_] = std::move(handler);
90 std::unique_lock<SharedMutex> lock(mutex_);
91 handlersMap_.erase(
id);
102 std::shared_lock<SharedMutex> lock(mutex_);
103 return handlersMap_.empty();
112 std::unique_lock<SharedMutex> lock(mutex_);
113 handlersMap_.clear();
117 std::unordered_map<SubscriberID, MessageHandler> handlersMap_;
118 mutable SharedMutex mutex_;
128template <
typename MessageType>
132 using MessageHandler =
133 std::function<void(
const std::string &,
const MessageType &)>;
134#if __cplusplus >= 201703L | defined _WIN32
135 using SharedMutex = std::shared_mutex;
137 using SharedMutex = std::shared_timed_mutex;
144 void publish(
const std::string &topicName,
const MessageType &message)
const
146 std::shared_ptr<Topic<MessageType>> topicPtr;
148 std::shared_lock<SharedMutex> lock(mutex_);
149 auto iter = topicMap_.find(topicName);
150 if (iter != topicMap_.end())
152 topicPtr = iter->second;
159 topicPtr->publish(message);
167 const MessageHandler &handler)
169 auto topicHandler = [topicName, handler](
const MessageType &message) {
170 handler(topicName, message);
172 return subscribeToTopic(topicName, std::move(topicHandler));
183 MessageHandler &&handler)
185 auto topicHandler = [topicName, handler = std::move(handler)](
186 const MessageType &message) {
187 handler(topicName, message);
189 return subscribeToTopic(topicName, std::move(topicHandler));
201 std::shared_lock<SharedMutex> lock(mutex_);
202 auto iter = topicMap_.find(topicName);
203 if (iter == topicMap_.end())
207 iter->second->unsubscribe(
id);
208 if (!iter->second->empty())
211 std::unique_lock<SharedMutex> lock(mutex_);
212 auto iter = topicMap_.find(topicName);
213 if (iter == topicMap_.end())
217 if (iter->second->empty())
218 topicMap_.erase(iter);
226 std::shared_lock<SharedMutex> lock(mutex_);
227 return topicMap_.size();
235 std::unique_lock<SharedMutex> lock(mutex_);
245 std::unique_lock<SharedMutex> lock(mutex_);
246 topicMap_.erase(topicName);
258 std::shared_ptr<Topic<MessageType>> topicPtr;
260 std::shared_lock<SharedMutex> lock(mutex_);
261 auto iter = topicMap_.find(topicName);
262 if (iter != topicMap_.end())
264 topicPtr = iter->second;
271 return topicPtr->empty();
275 std::unordered_map<std::string, std::shared_ptr<Topic<MessageType>>>
277 mutable SharedMutex mutex_;
278 SubscriberID subID_ = 0;
280 SubscriberID subscribeToTopic(
281 const std::string &topicName,
282 typename Topic<MessageType>::MessageHandler &&handler)
285 std::shared_lock<SharedMutex> lock(mutex_);
286 auto iter = topicMap_.find(topicName);
287 if (iter != topicMap_.end())
289 return iter->second->subscribe(std::move(handler));
292 std::unique_lock<SharedMutex> lock(mutex_);
293 auto iter = topicMap_.find(topicName);
294 if (iter != topicMap_.end())
296 return iter->second->subscribe(std::move(handler));
298 auto topicPtr = std::make_shared<Topic<MessageType>>();
299 auto id = topicPtr->subscribe(std::move(handler));
300 topicMap_[topicName] = std::move(topicPtr);
This class template implements a publish-subscribe pattern with multiple named topics.
Definition PubSubService.h:130
bool isTopicEmpty(const std::string &topicName) const
Check if a topic is empty.
Definition PubSubService.h:256
SubscriberID subscribe(const std::string &topicName, MessageHandler &&handler)
Subscribe to a topic. When a message is published to the topic, the handler is invoked by passing the...
Definition PubSubService.h:182
void clear()
remove all topics.
Definition PubSubService.h:233
void publish(const std::string &topicName, const MessageType &message) const
Publish a message to a topic. The message will be broadcasted to every subscriber.
Definition PubSubService.h:144
SubscriberID subscribe(const std::string &topicName, const MessageHandler &handler)
Subscribe to a topic. When a message is published to the topic, the handler is invoked by passing the...
Definition PubSubService.h:166
void unsubscribe(const std::string &topicName, SubscriberID id)
Unsubscribe from a topic.
Definition PubSubService.h:198
size_t size() const
return the number of topics.
Definition PubSubService.h:224
void removeTopic(const std::string &topicName)
Remove a topic.
Definition PubSubService.h:243
This class template presents an unnamed topic.
Definition PubSubService.h:36
void clear()
Remove all subscribers from the topic.
Definition PubSubService.h:110
bool empty() const
Check if the topic is empty.
Definition PubSubService.h:100
SubscriberID subscribe(const MessageHandler &handler)
Subscribe to the topic.
Definition PubSubService.h:65
void unsubscribe(SubscriberID id)
Unsubscribe from the topic.
Definition PubSubService.h:88
void publish(const MessageType &message) const
Publish a message, every subscriber in the topic will receive the message.
Definition PubSubService.h:50
SubscriberID subscribe(MessageHandler &&handler)
Subscribe to the topic.
Definition PubSubService.h:78
Drogon Test is a minimal effort test framework developed because the major C++ test frameworks doesn'...
Definition Attribute.h:23