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

Main server application that manages client connections and camera streaming. More...

#include <app.hpp>

Public Member Functions

 App (irsol::types::port_t port)
 Constructs the App.
 
bool start ()
 Starts the server.
 
void stop ()
 Stops the server.
 
std::shared_ptr< ClientSessiongetClientSession (const irsol::types::client_id_t &clientId)
 Retrieves an active client session.
 
void broadcastMessage (protocol::OutMessage &&message, const std::optional< irsol::types::client_id_t > &excludeClient=std::nullopt)
 Broadcasts a message to all connected clients.
 
camera::Interfacecamera ()
 Accessor for the camera interface.
 
frame_collector::FrameCollectorframeCollector ()
 Accessor for the frame collector.
 
const handlers::MessageHandlermessageHandler () const
 Accessor for the message handler.
 

Private Types

using client_map_t = std::unordered_map< irsol::types::client_id_t, std::shared_ptr< ClientSession > >
 

Private Member Functions

void addClient (const irsol::types::client_id_t &clientId, irsol::types::socket_t &&sock)
 Adds a new client session.
 
void removeClient (const irsol::types::client_id_t &clientId)
 Removes a client session.
 
void registerMessageHandlers ()
 Registers standard message handlers.
 
template<typename InMessageT , typename HandlerT , typename... Args>
void registerMessageHandler (const std::string &identifier, Args &&... args)
 Registers a message handler by type.
 
template<typename InMessageT , typename LambdaT >
void registerLambdaHandler (const std::string &identifier, std::shared_ptr< handlers::Context > ctx, LambdaT &&lambda)
 Registers a lambda-based message handler.
 

Private Attributes

const irsol::types::port_t m_port
 TCP port on which the server listens.
 
irsol::server::internal::ClientSessionAcceptor m_acceptor
 Acceptor that handles incoming client connections.
 
std::thread m_acceptThread
 Thread running the connection acceptor loop.
 
std::mutex m_clientsMutex
 Mutex for protecting access to m_clients.
 
client_map_t m_clients
 Map of connected clients.
 
std::unique_ptr< camera::Interfacem_cameraInterface
 Interface to the camera.
 
std::unique_ptr< frame_collector::FrameCollectorm_frameCollector
 Frame collector for capturing and broadcasting camera frames.
 
std::unique_ptr< handlers::MessageHandlerm_messageHandler
 Central handler for processing protocol messages.
 

Detailed Description

Main server application that manages client connections and camera streaming.

The App class starts the TCP server, listens for new connections, instantiates a new irsol::server::ClientSession per client, and coordinates the camera interface, frame collection, and message dispatching.

Definition at line 45 of file app.hpp.

Member Typedef Documentation

◆ client_map_t

using irsol::server::App::client_map_t = std::unordered_map<irsol::types::client_id_t, std::shared_ptr<ClientSession> >
private

Definition at line 47 of file app.hpp.

Constructor & Destructor Documentation

◆ App()

irsol::server::App::App ( irsol::types::port_t  port)
explicit

Constructs the App.

Parameters
portThe TCP port on which the server will listen for client connections.

Definition at line 13 of file app.cpp.

14 : m_port(port)
15 , m_acceptor(
16 m_port,
17 std::bind(&App::addClient, this, std::placeholders::_1, std::placeholders::_2))
18 , m_cameraInterface(std::make_unique<camera::Interface>(camera::Interface::HalfResolution()))
19 , m_frameCollector(std::make_unique<frame_collector::FrameCollector>(*m_cameraInterface.get()))
20 , m_messageHandler(std::make_unique<handlers::MessageHandler>())
21{
23}
static Interface HalfResolution()
Factory method to create a camera interface using half sensor resolution.
Definition interface.cpp:63
const irsol::types::port_t m_port
TCP port on which the server listens.
Definition app.hpp:121
irsol::server::internal::ClientSessionAcceptor m_acceptor
Acceptor that handles incoming client connections.
Definition app.hpp:124
void addClient(const irsol::types::client_id_t &clientId, irsol::types::socket_t &&sock)
Adds a new client session.
Definition app.cpp:85
std::unique_ptr< frame_collector::FrameCollector > m_frameCollector
Frame collector for capturing and broadcasting camera frames.
Definition app.hpp:139
void registerMessageHandlers()
Registers standard message handlers.
Definition app.cpp:132
std::unique_ptr< camera::Interface > m_cameraInterface
Interface to the camera.
Definition app.hpp:136
std::unique_ptr< handlers::MessageHandler > m_messageHandler
Central handler for processing protocol messages.
Definition app.hpp:142

Member Function Documentation

◆ addClient()

void irsol::server::App::addClient ( const irsol::types::client_id_t clientId,
irsol::types::socket_t &&  sock 
)
private

Adds a new client session.

Parameters
clientIdUnique ID for the client.
sockTCP socket for communication with the client.
Note
The new session is started on a separate thread.

Definition at line 85 of file app.cpp.

86{
87 auto session = std::make_shared<ClientSession>(clientId, std::move(sock), *this);
88 std::scoped_lock<std::mutex> lock(m_clientsMutex);
90 "Registering new client connection from {} with id {}",
91 session->socket().address().to_string(),
92 clientId);
93 {
94 m_clients.insert({clientId, session});
96 "Client {} added to session list, total clients: {}", clientId, m_clients.size());
97 }
98
99 IRSOL_LOG_INFO("Starting client session thread for client with id {}", clientId);
100 std::thread([session, this]() {
101 IRSOL_LOG_DEBUG("Thread for client with ID {} started", session->id());
102
103 try {
104 session->run();
105 } catch(std::exception& e) {
107 "Error in client session thread for client with id {}: {}", session->id(), e.what());
108 }
109 IRSOL_LOG_DEBUG("Thread for client with ID {} finished", session->id());
110 removeClient(session->id());
111 })
112 .detach();
113}
client_map_t m_clients
Map of connected clients.
Definition app.hpp:133
void removeClient(const irsol::types::client_id_t &clientId)
Removes a client session.
Definition app.cpp:116
std::mutex m_clientsMutex
Mutex for protecting access to m_clients.
Definition app.hpp:130
#define IRSOL_LOG_INFO(...)
Logs an info-level message using the default logger.
Definition logging.hpp:92
#define IRSOL_LOG_ERROR(...)
Logs an error-level message using the default logger.
Definition logging.hpp:94
#define IRSOL_LOG_DEBUG(...)
Logs a debug-level message using the default logger.
Definition logging.hpp:91

◆ broadcastMessage()

void irsol::server::App::broadcastMessage ( protocol::OutMessage &&  message,
const std::optional< irsol::types::client_id_t > &  excludeClient = std::nullopt 
)

Broadcasts a message to all connected clients.

Parameters
messageThe message to send.
excludeClientOptional client to exclude (e.g., the sender).

This method is thread-safe and will skip the excluded client if specified.

Definition at line 61 of file app.cpp.

64{
65 // Serialize the message only once, and distribute to all clients
66 auto serializedMessage = irsol::protocol::Serializer::serialize(std::move(message));
67 IRSOL_LOG_DEBUG("Broadcasting serialized message {}", serializedMessage.toString());
68 std::scoped_lock<std::mutex> lock(m_clientsMutex);
69
70 for(const auto& [clientId, session] : m_clients) {
71 if(excludeClient && clientId == *excludeClient) {
72 continue; // Skip the sender if specified
73 }
74 try {
75 std::scoped_lock<std::mutex> sessionLock(session->socketMutex());
76 session->handleSerializedMessage(serializedMessage);
77 } catch(const std::exception& ex) {
78 IRSOL_LOG_WARN("Failed to send broadcast to client {}: {}", clientId, ex.what());
79 }
80 }
81 IRSOL_LOG_DEBUG("Broadcasting complete.");
82}
static internal::SerializedMessage serialize(OutMessage &&msg)
Serialize an irsol::protocol::OutMessage variant into a serialized protocol message.
#define IRSOL_LOG_WARN(...)
Logs a warning-level message using the default logger.
Definition logging.hpp:93

◆ camera()

camera::Interface & irsol::server::App::camera ( )
inline

Accessor for the camera interface.

Returns
Reference to the owned camera interface.

Definition at line 96 of file app.hpp.

97 {
98 return *m_cameraInterface;
99 };

◆ frameCollector()

frame_collector::FrameCollector & irsol::server::App::frameCollector ( )
inline

Accessor for the frame collector.

Returns
Reference to the owned frame collector.

Definition at line 105 of file app.hpp.

106 {
107 return *m_frameCollector;
108 }

◆ getClientSession()

std::shared_ptr< ClientSession > irsol::server::App::getClientSession ( const irsol::types::client_id_t clientId)

Retrieves an active client session.

Parameters
clientIdThe unique ID of the client.
Returns
Shared pointer to the client session, or nullptr if not found.

Definition at line 53 of file app.cpp.

54{
55 std::scoped_lock<std::mutex> lock(m_clientsMutex);
56 auto it = m_clients.find(clientId);
57 return it != m_clients.end() ? it->second : nullptr;
58}

◆ messageHandler()

const handlers::MessageHandler & irsol::server::App::messageHandler ( ) const
inline

Accessor for the message handler.

Returns
Const reference to the owned message handler.

Definition at line 114 of file app.hpp.

115 {
116 return *m_messageHandler;
117 }

◆ registerLambdaHandler()

template<typename InMessageT , typename LambdaT >
void irsol::server::App::registerLambdaHandler ( const std::string &  identifier,
std::shared_ptr< handlers::Context ctx,
LambdaT &&  lambda 
)
inlineprivate

Registers a lambda-based message handler.

Template Parameters
InMessageTIncoming message type.
LambdaTType of the lambda handler.
Parameters
identifierHandler identifier.
ctxHandler context.
lambdaLambda function to invoke for the message.

Example:

registerLambdaHandler<protocol::Command>(
"custom_cmd",
ctx,
[](std::shared_ptr<handlers::Context> ctx, const irsol::types::client_id_t& clientId,
protocol::Command&& cmd) { return std::vector<protocol::OutMessage>{...};
}
);
std::string client_id_t
Represents a unique client identifier. Typically used to identify connected clients by string IDs.
Definition types.hpp:55
Represents a command invocation in the protocol.
Definition command.hpp:33

Definition at line 213 of file app.hpp.

217 {
218 auto handler = handlers::makeLambdaHandler<InMessageT>(ctx, std::forward<LambdaT>(lambda));
220
221 if(!messageHandler.template registerHandler<InMessageT>(identifier, handler)) {
222 IRSOL_LOG_FATAL("Failed to register lambda handler for identifier {}", identifier);
223 throw std::runtime_error(
224 "Failed to register lambda handler for identifier '" + identifier + "'");
225 }
226 }
const handlers::MessageHandler & messageHandler() const
Accessor for the message handler.
Definition app.hpp:114
#define IRSOL_LOG_FATAL(...)
Logs a fatal (critical) message using the default logger.
Definition logging.hpp:95
constexpr auto makeHandler(std::shared_ptr< Context > ctx, Args &&... args)
Constructs a handler instance of the given type.
Definition factory.hpp:28

◆ registerMessageHandler()

template<typename InMessageT , typename HandlerT , typename... Args>
void irsol::server::App::registerMessageHandler ( const std::string &  identifier,
Args &&...  args 
)
inlineprivate

Registers a message handler by type.

Template Parameters
InMessageTIncoming message type.
HandlerTHandler class for the message.
ArgsConstructor arguments for the handler.
Parameters
identifierMessage handler identifier string.
argsArguments to construct the handler.

Example:

registerMessageHandler<protocol::Command, handlers::CommandFRHandler>("fr", ctx);

Definition at line 182 of file app.hpp.

183 {
184 auto handler = handlers::makeHandler<HandlerT>(std::forward<Args>(args)...);
186
187 if(!messageHandler.template registerHandler<InMessageT>(identifier, handler)) {
188 IRSOL_LOG_FATAL("Failed to register handler for identifier {}", identifier);
189 throw std::runtime_error("Failed to register handler for identifier '" + identifier + "'");
190 }
191 }

◆ registerMessageHandlers()

void irsol::server::App::registerMessageHandlers ( )
private

Registers standard message handlers.

Sets up the message handler registry with known message-handler mappings.

Definition at line 132 of file app.cpp.

133{
134 // Build a context to pass to all handlers
135 auto ctx = std::make_shared<irsol::server::handlers::Context>(*this);
136
137 // Register message handlers for specific message types
138 registerMessageHandler<protocol::Inquiry, handlers::InquiryFrameRateHandler>("fr", ctx);
139 registerMessageHandler<protocol::Assignment, handlers::AssignmentFrameRateHandler>("fr", ctx);
140 registerMessageHandler<protocol::Assignment, handlers::AssignmentInputSequenceLengthHandler>(
141 "isl", ctx);
142 registerMessageHandler<protocol::Assignment, handlers::AssignmentIntegrationTimeHandler>(
143 "it", ctx);
144 registerMessageHandler<protocol::Inquiry, handlers::InquiryIntegrationTimeHandler>("it", ctx);
145 registerMessageHandler<protocol::Inquiry, handlers::InquiryInputSequenceLengthHandler>(
146 "isl", ctx);
147 registerMessageHandler<protocol::Command, handlers::CommandAbortHandler>("abort", ctx);
148 registerMessageHandler<protocol::Command, handlers::CommandGIHandler>("gi", ctx);
149 registerMessageHandler<protocol::Command, handlers::CommandGISHandler>("gis", ctx);
150 registerMessageHandler<protocol::Inquiry, handlers::InquiryImgLeftHandler>("img_l", ctx);
151 registerMessageHandler<protocol::Inquiry, handlers::InquiryImgTopHandler>("img_t", ctx);
152 registerMessageHandler<protocol::Inquiry, handlers::InquiryImgWidthHandler>("img_w", ctx);
153 registerMessageHandler<protocol::Inquiry, handlers::InquiryImgHeightHandler>("img_h", ctx);
154 registerMessageHandler<protocol::Assignment, handlers::AssignmentImgLeftHandler>("img_l", ctx);
155 registerMessageHandler<protocol::Assignment, handlers::AssignmentImgTopHandler>("img_t", ctx);
156 registerMessageHandler<protocol::Assignment, handlers::AssignmentImgWidthHandler>("img_w", ctx);
157 registerMessageHandler<protocol::Assignment, handlers::AssignmentImgHeightHandler>("img_h", ctx);
158
159 registerLambdaHandler<protocol::Command>(
160 "image_data",
161 ctx,
162 [](
163 std::shared_ptr<handlers::Context> ctx,
164 std::shared_ptr<irsol::server::ClientSession> client,
165 protocol::Command&& cmd) -> std::vector<protocol::OutMessage> {
166 std::vector<protocol::OutMessage> result;
167 auto& cam = ctx->app.camera();
168 auto img = cam.captureImage(std::chrono::milliseconds(10000));
169
170 if(img.IsEmpty()) {
171 IRSOL_NAMED_LOG_ERROR(client->id(), "Failed to capture image.");
172 result.emplace_back(irsol::protocol::Error::from(cmd, "Failed to capture image"));
173 return result;
174 }
175
176 uint32_t width = static_cast<uint32_t>(img.GetWidth());
177 uint32_t height = static_cast<uint32_t>(img.GetHeight());
178 size_t dataSize = img.GetSize();
179
180 const void* imageBuffer = img.GetImageData();
181 std::vector<irsol::types::byte_t> rawData(dataSize);
182 memcpy(rawData.data(), imageBuffer, dataSize);
183
184 result.emplace_back(
185 irsol::protocol::ImageBinaryData(std::move(rawData), {height, width}, {}));
186 return result;
187 });
188}
Represents a binary data object within the protocol.
Definition binary.hpp:107
auto result

◆ removeClient()

void irsol::server::App::removeClient ( const irsol::types::client_id_t clientId)
private

Removes a client session.

Parameters
clientIdID of the client to disconnect and clean up.

This is typically called automatically when the client disconnects or times out.

Definition at line 116 of file app.cpp.

117{
118 std::scoped_lock<std::mutex> lock(m_clientsMutex);
119 auto clientIt = m_clients.find(clientId);
120 if(clientIt == m_clients.end()) {
121 IRSOL_LOG_ERROR("Client '{}' not found in session list", clientId);
122 } else {
123 auto client = clientIt->second;
124 m_frameCollector->deregisterClient(client->id());
125 m_clients.erase(clientIt);
127 "Client {} removed from session list, remaining clients: {}", clientId, m_clients.size());
128 }
129}

◆ start()

bool irsol::server::App::start ( )

Starts the server.

Returns
True if the server starts successfully, false otherwise.

This starts the acceptor thread, initializes camera and message handlers, and prepares the system for client interaction.

Definition at line 26 of file app.cpp.

27{
28 if(!m_acceptor.isOpen()) {
29 IRSOL_LOG_ERROR("Failed to open acceptor on port {}: {}", m_port, m_acceptor.error());
30 return false;
31 }
32 IRSOL_LOG_DEBUG("Starting accept thread");
34 IRSOL_LOG_INFO("Server started successfully");
35 return true;
36}
std::thread m_acceptThread
Thread running the connection acceptor loop.
Definition app.hpp:127
bool isOpen() const
Checks if the acceptor is actively listening.
Definition acceptor.cpp:27
std::string error() const
Gets the current error message, if any.
Definition acceptor.cpp:20
void run()
Starts the accept loop.
Definition acceptor.cpp:44

◆ stop()

void irsol::server::App::stop ( )

Stops the server.

Gracefully shuts down client sessions, stops the frame collector, and joins the acceptor thread.

Definition at line 39 of file app.cpp.

40{
41 IRSOL_LOG_INFO("Stopping server");
43
44 if(m_acceptThread.joinable()) {
45 IRSOL_LOG_DEBUG("Joining accept thread");
46 m_acceptThread.join();
47 }
48 m_frameCollector->stop();
49 IRSOL_LOG_INFO("Server stopped");
50}

Member Data Documentation

◆ m_acceptor

irsol::server::internal::ClientSessionAcceptor irsol::server::App::m_acceptor
private

Acceptor that handles incoming client connections.

Definition at line 124 of file app.hpp.

◆ m_acceptThread

std::thread irsol::server::App::m_acceptThread
private

Thread running the connection acceptor loop.

Definition at line 127 of file app.hpp.

◆ m_cameraInterface

std::unique_ptr<camera::Interface> irsol::server::App::m_cameraInterface
private

Interface to the camera.

Definition at line 136 of file app.hpp.

◆ m_clients

client_map_t irsol::server::App::m_clients
private

Map of connected clients.

Definition at line 133 of file app.hpp.

◆ m_clientsMutex

std::mutex irsol::server::App::m_clientsMutex
private

Mutex for protecting access to m_clients.

Definition at line 130 of file app.hpp.

◆ m_frameCollector

std::unique_ptr<frame_collector::FrameCollector> irsol::server::App::m_frameCollector
private

Frame collector for capturing and broadcasting camera frames.

Definition at line 139 of file app.hpp.

◆ m_messageHandler

std::unique_ptr<handlers::MessageHandler> irsol::server::App::m_messageHandler
private

Central handler for processing protocol messages.

Definition at line 142 of file app.hpp.

◆ m_port

const irsol::types::port_t irsol::server::App::m_port
private

TCP port on which the server listens.

Definition at line 121 of file app.hpp.


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