MessageBus¶
Examples/MessageBus¶
#include <SevenBit/DI.hpp>
#include <any>
#include <chrono>
#include <functional>
#include <iostream>
#include <thread>
#include <unordered_map>
using namespace sb::di;
using namespace std::chrono_literals;
struct IMessageBus
{
virtual void send(const std::any &message) = 0;
virtual void on(std::type_index typeId, std::function<void(const std::any &)> callback) = 0;
template <class T, class F> void on(F f)
{
on(typeid(T), [f](const std::any &msg) { f(std::any_cast<const T &>(msg)); });
}
virtual ~IMessageBus() = default;
};
class MessageBus final : public IMessageBus
{
std::unordered_map<std::type_index, std::vector<std::function<void(const std::any &)>>> _callbacks;
public:
void send(const std::any &message) override
{
if (const auto it = _callbacks.find(message.type()); it != _callbacks.end())
{
for (const auto &callback : it->second)
{
callback(message);
}
}
}
void on(const std::type_index typeId, std::function<void(const std::any &)> callback) override
{
_callbacks[typeId].emplace_back(std::move(callback));
}
};
struct TickMessage
{
int number;
std::chrono::milliseconds delay;
};
class SenderService
{
IMessageBus &_messageBus;
public:
explicit SenderService(IMessageBus &messageBus) : _messageBus(messageBus) {}
void run(const int ticksCount, const std::chrono::milliseconds delay) const
{
for (int i = 1; i <= ticksCount; ++i)
{
const auto realDelay = sleepFor(delay);
_messageBus.send(TickMessage{i, realDelay});
}
}
private:
[[nodiscard]] std::chrono::milliseconds sleepFor(const std::chrono::milliseconds delay) const
{
const auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(delay);
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
}
};
class ReceiverService
{
IMessageBus &_messageBus;
public:
explicit ReceiverService(IMessageBus &messageBus) : _messageBus(messageBus)
{
_messageBus.on<TickMessage>([&](const TickMessage &message) { onReceived(message); });
}
void onReceived(const TickMessage &message) const
{
std::cout << "Received tick message no: " << message.number << ", delay: " << message.delay.count() << "ms"
<< std::endl;
}
};
int main()
{
ServiceProvider provider = ServiceCollection{}
.addSingleton<IMessageBus, MessageBus>()
.addSingleton<SenderService>()
.addSingleton<ReceiverService>()
.buildServiceProvider();
const auto &receiver = provider.getService<ReceiverService>(); // force construction
const auto &sender = provider.getService<SenderService>();
sender.run(5, 200ms);
return 0;
}