IRSOL
C++ code implementing socket server for interacting with Baumer camera.
irsol::server::handlers::MessageHandler Class Reference

Binds incoming protocol messages to the appropriate per-client logic. More...

#include <message_handler.hpp>

Public Member Functions

handling_function_response_t handle (const irsol::types::client_id_t &clientId, protocol::InMessage &&message) const
 Dispatches an incoming message to the correct user-defined handler.
 
template<typename T , std::enable_if_t< irsol::traits::is_type_in_variant< T, irsol::protocol::InMessage >::value, int > = 0>
bool registerHandler (const std::string &identifier, handler_function_t< T > handler)
 Registers a user-defined handler for a specific message type and identifier.
 

Private Types

using handling_function_response_t = std::vector< protocol::OutMessage >
 
using handler_identifier_t = std::string
 
template<typename T >
using handler_function_t = std::function< handling_function_response_t(const irsol::types::client_id_t &, T &&)>
 
using assignment_handler_function_t = handler_function_t< protocol::Assignment && >
 
using inquiry_handler_function_t = handler_function_t< protocol::Inquiry && >
 
using command_handler_function_t = handler_function_t< protocol::Command && >
 
template<typename T >
using message_handler_map_t = std::unordered_map< handler_identifier_t, T >
 
using assignment_message_handler_map_t = message_handler_map_t< assignment_handler_function_t >
 
using inquiry_message_handler_map_t = message_handler_map_t< inquiry_handler_function_t >
 
using command_message_handler_map_t = message_handler_map_t< command_handler_function_t >
 
using any_handler_function_t = std::variant< assignment_handler_function_t, inquiry_handler_function_t, command_handler_function_t >
 

Private Member Functions

std::optional< any_handler_function_tfindHandlerForMessage (const protocol::InMessage &msg) const
 Locates a registered handler (of any message type) for a given message.
 
template<typename T , std::enable_if_t< irsol::traits::is_type_in_variant< T, irsol::protocol::InMessage >::value, int > = 0>
std::optional< handler_function_t< T > > findHandler (const handler_identifier_t &identifier) const
 Locates a handler of a specific message type and identifier.
 

Private Attributes

assignment_message_handler_map_t m_assignmentMessageHandlers {}
 Registered handlers for Assignment messages, keyed by identifier.
 
inquiry_message_handler_map_t m_inquiryMessageHandlers {}
 Registered handlers for Inquiry messages, keyed by identifier.
 
command_message_handler_map_t m_commandMessageHandlers {}
 Registered handlers for Command messages, keyed by identifier.
 

Detailed Description

Binds incoming protocol messages to the appropriate per-client logic.

This class acts as a central dispatcher used by the application layer irsol::server::App to process structured incoming messages irsol::protocol::InMessage. Each message is handled by a user-registered callback function based on its type and identifier.

Messages are categorized into three types:

For each type, client-specific logic is registered using registerHandler(). When a message arrives, handle() invokes the matching callback and returns the generated response messages to be sent back to the client.

Definition at line 52 of file message_handler.hpp.

Member Typedef Documentation

◆ any_handler_function_t

◆ assignment_handler_function_t

◆ assignment_message_handler_map_t

◆ command_handler_function_t

◆ command_message_handler_map_t

◆ handler_function_t

◆ handler_identifier_t

◆ handling_function_response_t

◆ inquiry_handler_function_t

◆ inquiry_message_handler_map_t

◆ message_handler_map_t

Definition at line 66 of file message_handler.hpp.

Member Function Documentation

◆ findHandler()

std::optional< handler_function_t< T > > irsol::server::handlers::MessageHandler::findHandler ( const handler_identifier_t identifier) const
inlineprivate

Locates a handler of a specific message type and identifier.

Template Parameters
TMessage type (Assignment, Inquiry, or Command).
Parameters
identifierIdentifier of the message to match.
Returns
A callable if found, or std::nullopt if no handler is registered.

Definition at line 160 of file message_handler.hpp.

161 {
162 if constexpr(std::is_same_v<T, protocol::Assignment>) {
163 auto it = m_assignmentMessageHandlers.find(identifier);
164 return it == m_assignmentMessageHandlers.end() ? std::nullopt
165 : std::make_optional(it->second);
166 } else if constexpr(std::is_same_v<T, protocol::Inquiry>) {
167 auto it = m_inquiryMessageHandlers.find(identifier);
168 return it == m_inquiryMessageHandlers.end() ? std::nullopt : std::make_optional(it->second);
169 } else if constexpr(std::is_same_v<T, protocol::Command>) {
170 auto it = m_commandMessageHandlers.find(identifier);
171 return it == m_commandMessageHandlers.end() ? std::nullopt : std::make_optional(it->second);
172 } else {
174 }
175 }
assignment_message_handler_map_t m_assignmentMessageHandlers
Registered handlers for Assignment messages, keyed by identifier.
inquiry_message_handler_map_t m_inquiryMessageHandlers
Registered handlers for Inquiry messages, keyed by identifier.
command_message_handler_map_t m_commandMessageHandlers
Registered handlers for Command messages, keyed by identifier.
#define IRSOL_MISSING_TEMPLATE_SPECIALIZATION(T, funcNameLiteral)
Emits a compile-time error when no template specialization is available.
Definition macros.hpp:173
constexpr auto makeHandler(std::shared_ptr< Context > ctx, Args &&... args)
Constructs a handler instance of the given type.
Definition factory.hpp:28

◆ findHandlerForMessage()

std::optional< MessageHandler::any_handler_function_t > irsol::server::handlers::MessageHandler::findHandlerForMessage ( const protocol::InMessage msg) const
private

Locates a registered handler (of any message type) for a given message.

Parameters
msgThe message whose identifier and type are used for lookup.
Returns
A matching handler wrapped in a std::variant, or std::nullopt if not found.

Definition at line 42 of file message_handler.cpp.

43{
44 return std::visit(
45 [this](auto&& value) -> std::optional<any_handler_function_t> {
46 using T = std::decay_t<decltype(value)>;
47 auto res = this->findHandler<T>(value.identifier);
48 if(!res) {
49 return std::nullopt;
50 }
51 return std::make_optional<any_handler_function_t>(*res);
52 },
53 msg);
54}
auto value
auto msg

◆ handle()

MessageHandler::handling_function_response_t irsol::server::handlers::MessageHandler::handle ( const irsol::types::client_id_t clientId,
protocol::InMessage &&  message 
) const

Dispatches an incoming message to the correct user-defined handler.

This method extracts the message type and identifier from the parsed InMessage, then finds the corresponding callback registered via registerHandler(). The appropriate handler is invoked with the clientId and the message payload.

Parameters
clientIdUnique identifier of the client sending the message.
messageThe parsed incoming message to handle.
Returns
A list of OutMessage responses to be sent back to the client.

Definition at line 11 of file message_handler.cpp.

13{
14 IRSOL_LOG_TRACE("Handling message: '{}' for client '{}'", protocol::toString(message), clientId);
16 if(!handler) {
17 IRSOL_LOG_ERROR("No handler found for message: '{}'", irsol::protocol::toString(message));
18 std::vector<protocol::OutMessage> result;
19 result.emplace_back(
20 protocol::Error::from(std::move(message), "No handler registered for this message."));
21 return result;
22 }
23 // Dispatch the message to the appropriate handler and return the response
24 const std::string messageString = protocol::toString(message);
25
26 try {
27 return std::visit(
29 using T = std::decay_t<decltype(msg)>;
30 using handler_function_t = MessageHandler::handler_function_t<T>;
31 return std::get<handler_function_t>(*handler)(clientId, std::move(msg));
32 },
33 std::move(message));
34
35 } catch(const std::exception& e) {
36 IRSOL_LOG_ERROR("Error handling message: '{}': {}", messageString, e.what());
37 return {};
38 }
39}
std::function< handling_function_response_t(const irsol::types::client_id_t &, T &&)> handler_function_t
std::optional< any_handler_function_t > findHandlerForMessage(const protocol::InMessage &msg) const
Locates a registered handler (of any message type) for a given message.
std::vector< protocol::OutMessage > handling_function_response_t
#define IRSOL_LOG_ERROR(...)
Logs an error-level message using the default logger.
Definition logging.hpp:94
#define IRSOL_LOG_TRACE(...)
Logs a trace-level message using the default logger.
Definition logging.hpp:90
std::string toString(const InMessage &msg)
Converts an incoming message variant to a human-readable string.
Definition variants.cpp:19
static Error from(const T &msg, const std::string &description)
Creates an error from a specific incoming message type.
Definition error.hpp:63
auto result

◆ registerHandler()

bool irsol::server::handlers::MessageHandler::registerHandler ( const std::string &  identifier,
handler_function_t< T handler 
)
inline

Registers a user-defined handler for a specific message type and identifier.

Handlers must be registered per message identifier (e.g., "start_stream", "set_param"), and per message kind (Assignment, Inquiry, Command). Duplicate registrations are rejected.

Template Parameters
TOne of protocol::Assignment, protocol::Inquiry, or protocol::Command.
Parameters
identifierThe string identifier of the message (e.g., the name field).
handlerA callable accepting (client_id_t, T&&) and returning response messages.
Returns
true if the handler was successfully registered, false if a duplicate exists.

Definition at line 106 of file message_handler.hpp.

107 {
108 // Make sure there's no duplicate handlers for the same message kind and identifier
109 if(auto existingHandler = findHandler<T>(identifier); existingHandler) {
110 if constexpr(std::is_same_v<T, protocol::Assignment>) {
112 "Duplicate handler registered for identifier '{}' and Assignment type", identifier);
113 } else if constexpr(std::is_same_v<T, protocol::Inquiry>) {
115 "Duplicate handler registered for identifier '{}' and Inquiry type", identifier);
116 } else if constexpr(std::is_same_v<T, protocol::Command>) {
118 "Duplicate handler registered for identifier '{}' and Command type", identifier);
119 } else {
120 IRSOL_MISSING_TEMPLATE_SPECIALIZATION(T, "registerHandler()");
121 }
122
123 return false;
124 }
125
126 if constexpr(std::is_same_v<T, protocol::Assignment>) {
127 IRSOL_LOG_INFO("Registering handler for 'Assignment(\"{}\")'", identifier);
129 } else if constexpr(std::is_same_v<T, protocol::Inquiry>) {
130 IRSOL_LOG_INFO("Registering handler for 'Inquiry(\"{}\")'", identifier);
131 m_inquiryMessageHandlers[identifier] = handler;
132 } else if constexpr(std::is_same_v<T, protocol::Command>) {
133 IRSOL_LOG_INFO("Registering handler for 'Command(\"{}\")'", identifier);
134 m_commandMessageHandlers[identifier] = handler;
135 } else {
136 IRSOL_MISSING_TEMPLATE_SPECIALIZATION(T, "registerHandler()");
137 }
138 return true;
139 }
#define IRSOL_LOG_INFO(...)
Logs an info-level message using the default logger.
Definition logging.hpp:92

Member Data Documentation

◆ m_assignmentMessageHandlers

assignment_message_handler_map_t irsol::server::handlers::MessageHandler::m_assignmentMessageHandlers {}
private

Registered handlers for Assignment messages, keyed by identifier.

Definition at line 178 of file message_handler.hpp.

178{};

◆ m_commandMessageHandlers

command_message_handler_map_t irsol::server::handlers::MessageHandler::m_commandMessageHandlers {}
private

Registered handlers for Command messages, keyed by identifier.

Definition at line 184 of file message_handler.hpp.

184{};

◆ m_inquiryMessageHandlers

inquiry_message_handler_map_t irsol::server::handlers::MessageHandler::m_inquiryMessageHandlers {}
private

Registered handlers for Inquiry messages, keyed by identifier.

Definition at line 181 of file message_handler.hpp.

181{};

The documentation for this class was generated from the following files: