add message passing system

This commit is contained in:
scawful
2024-08-14 23:46:17 -04:00
parent 3bbbc89001
commit 97959f2ac7
2 changed files with 260 additions and 0 deletions

131
src/app/core/message.cc Normal file
View File

@@ -0,0 +1,131 @@
#include "message.h"
namespace yaze {
namespace app {
namespace core {
#pragma mark - MessageDispatcher
void MessageDispatcher::RegisterListener(const std::string& message_type,
IMessageListener* listener) {
listeners_[message_type].push_back(listener);
}
void MessageDispatcher::UnregisterListener(const std::string& message_type,
IMessageListener* listener) {
auto& listener_list = listeners_[message_type];
listener_list.erase(
std::remove(listener_list.begin(), listener_list.end(), listener),
listener_list.end());
}
void MessageDispatcher::RegisterProtocol(IMessageProtocol* protocol) {
protocols_.push_back(protocol);
}
void MessageDispatcher::RegisterFilteredListener(
const std::string& message_type, IMessageListener* listener,
std::unique_ptr<MessageFilter> filter) {
filtered_listeners_[message_type].push_back({listener, std::move(filter)});
}
void MessageDispatcher::BindHandler(const std::string& message_type,
MessageHandler handler) {
handlers_[message_type].push_back(handler);
}
void MessageDispatcher::SendMessage(const Message& message) {
const auto& listener_list = listeners_[message.type];
for (auto listener : listener_list) {
listener->OnMessageReceived(message);
}
}
void MessageDispatcher::DispatchMessage(const Message& message) {
for (auto protocol : protocols_) {
if (protocol->CanHandleMessage(message)) {
return;
}
}
const auto& listener_list = listeners_[message.type];
for (auto listener : listener_list) {
listener->OnMessageReceived(message);
}
const auto& filtered_listener_list = filtered_listeners_[message.type];
for (auto& listener : filtered_listener_list) {
if (listener.filter->ShouldReceiveMessage(message)) {
listener.listener->OnMessageReceived(message);
}
}
const auto& handler_list = handlers_[message.type];
for (auto& handler : handler_list) {
handler(message);
}
}
#pragma mark - AsyncMessageDispatcher
void AsyncMessageDispatcher::Start() {
// Start a new thread and run the message loop.
}
void AsyncMessageDispatcher::Stop() {
// Stop the message loop and join the thread.
}
void AsyncMessageDispatcher::EnqueueMessage(const Message& message) {
// Enqueue a message to the message loop.
}
void AsyncMessageDispatcher::DispatchLoop() {
// Dispatch messages in a loop.
}
#pragma mark - MessageFilter
template <typename T>
void Swizzler::Swizzle(T* instance, void (T::*original_method)(),
std::function<void()> new_method) {
original_methods_[instance] = original_method;
swizzled_methods_[instance] = new_method;
}
template <typename T>
void Swizzler::CallOriginal(T* instance) {
auto it = original_methods_.find(instance);
if (it != original_methods_.end()) {
(instance->*(it->second))();
}
}
template <typename T>
void Swizzler::CallSwizzled(T* instance) {
auto it = swizzled_methods_.find(instance);
if (it != swizzled_methods_.end()) {
it->second();
}
}
#pragma mark - ObjectFactory
template <typename T>
void ObjectFactory::RegisterType(const std::string& type_name) {
creators_[type_name] = []() { return std::make_unique<T>(); };
}
std::unique_ptr<Reflectable> ObjectFactory::CreateObject(
const std::string& object_name) const {
auto it = creators_.find(object_name);
if (it != creators_.end()) {
return it->second();
}
return nullptr;
}
} // namespace core
} // namespace app
} // namespace yaze

129
src/app/core/message.h Normal file
View File

@@ -0,0 +1,129 @@
#ifndef YAZE_APP_CORE_MESSAGE_H
#define YAZE_APP_CORE_MESSAGE_H
#include <any>
#include <functional>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
namespace yaze {
namespace app {
namespace core {
struct Message {
std::string type;
void* sender;
std::any payload;
Message(const std::string& type, void* sender, const std::any& payload)
: type(type), sender(sender), payload(payload) {}
};
class IMessageListener {
public:
virtual ~IMessageListener() = default;
virtual void OnMessageReceived(const Message& message) = 0;
};
class IMessageProtocol {
public:
virtual ~IMessageProtocol() = default;
virtual bool CanHandleMessage(const Message& message) const = 0;
};
class MessageFilter {
public:
virtual ~MessageFilter() = default;
virtual bool ShouldReceiveMessage(const Message& message) const = 0;
};
using MessageHandler = std::function<void(const Message&)>;
class MessageDispatcher {
public:
void RegisterListener(const std::string& message_type,
IMessageListener* listener);
void UnregisterListener(const std::string& message_type,
IMessageListener* listener);
void RegisterProtocol(IMessageProtocol* protocol);
void RegisterFilteredListener(const std::string& message_type,
IMessageListener* listener,
std::unique_ptr<MessageFilter> filter);
void BindHandler(const std::string& message_type, MessageHandler handler);
void SendMessage(const Message& message);
void DispatchMessage(const Message& message);
private:
struct ListenerWithFilter {
IMessageListener* listener;
std::unique_ptr<MessageFilter> filter;
};
std::unordered_map<std::string, std::vector<IMessageListener*>> listeners_;
std::unordered_map<std::string, std::vector<ListenerWithFilter>>
filtered_listeners_;
std::unordered_map<std::string, std::vector<MessageHandler>> handlers_;
std::vector<IMessageProtocol*> protocols_;
};
class AsyncMessageDispatcher : public MessageDispatcher {
public:
void Start();
void Stop();
void EnqueueMessage(const Message& message);
private:
void DispatchLoop();
std::queue<Message> messageQueue_;
std::mutex queueMutex_;
std::thread dispatchThread_;
bool running_ = false;
};
class Swizzler {
public:
template <typename T>
void Swizzle(T* instance, void (T::*original_method)(),
std::function<void()> new_method);
template <typename T>
void CallOriginal(T* instance);
template <typename T>
void CallSwizzled(T* instance);
private:
std::unordered_map<void*, std::function<void()>> swizzled_methods_;
std::unordered_map<void*, void*> original_methods_;
};
class Reflectable {
public:
virtual ~Reflectable() = default;
virtual std::string GetTypeName() const = 0;
virtual std::vector<std::string> GetPropertyNames() const = 0;
virtual std::any GetPropertyValue(const std::string& property_name) const = 0;
virtual void SetPropertyValue(const std::string& property_name,
const std::any& value) = 0;
};
class ObjectFactory {
public:
template <typename T>
void RegisterType(const std::string& type_name);
std::unique_ptr<Reflectable> CreateObject(const std::string& type_name) const;
private:
std::unordered_map<std::string, std::function<std::unique_ptr<Reflectable>()>>
creators_;
};
} // namespace core
} // namespace app
} // namespace yaze
#endif // YAZE_APP_CORE_MESSAGE_H