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

Represents a single connected client session. More...

#include <session.hpp>

Public Member Functions

 ClientSession (const irsol::types::client_id_t &id, irsol::types::socket_t &&sock, App &app)
 Constructs a new ClientSession.
 
void run ()
 Starts the client's session logic.
 
void handleOutMessages (std::vector< protocol::OutMessage > &&messages)
 Handles multiple outbound messages to the client.
 
void handleOutMessage (protocol::OutMessage &&message)
 Handles a single outbound message to the client.
 
void handleSerializedMessage (const protocol::internal::SerializedMessage &serializedMessage)
 Sends an already-serialized message to the client.
 
const Appapp () const
 Returns a const reference to the owning App instance.
 
Appapp ()
 Returns a mutable reference to the owning App instance.
 
const irsol::types::client_id_tid () const
 Returns the unique client identifier.
 
const irsol::types::socket_tsocket () const
 Returns a const reference to the client socket.
 
irsol::types::socket_tsocket ()
 Returns a mutable reference to the client socket.
 
std::mutex & socketMutex ()
 Returns a reference to the socket mutex used for synchronization.
 
const irsol::server::internal::UserSessionDatauserData () const
 Returns a const reference to client-specific session state.
 
irsol::server::internal::UserSessionDatauserData ()
 Returns a mutable reference to client-specific session state.
 

Private Member Functions

void processInMessageBuffer (std::string &messageBuffer)
 Processes accumulated raw data into complete protocol messages.
 
void processInRawMessage (const std::string &rawMessage)
 Parses and processes a complete incoming raw message.
 
void send (const std::string &message)
 Sends a text message over the socket to the client.
 
void send (const irsol::types::byte_t *const data, size_t size)
 Sends binary data over the socket.
 

Private Attributes

irsol::types::client_id_t m_id
 Unique ID identifying this session (maps to client_id_t).
 
irsol::types::socket_t m_socket
 Socket used for communication with the client.
 
std::mutex m_socketMutex {}
 Mutex to synchronize socket access from multiple threads.
 
irsol::server::internal::UserSessionData m_sessionData {}
 Session-specific data (e.g., stream rate, frame subscriptions).
 
Appm_app
 Reference to the central App instance for server-wide coordination.
 

Detailed Description

Represents a single connected client session.

Each instance of ClientSession corresponds to exactly one connected client. It owns the socket connection, manages message transmission and reception, and encapsulates session-specific state (e.g., frame stream preferences).

The class is responsible for all communication with the client: reading inbound messages from the socket, parsing and dispatching them, and sending outbound messages. All session-specific state is stored here, including a irsol::server::internal::UserSessionData structure.

In addition, the session holds a reference to the central irsol::server::App instance, which enables it to interact with the global server context (e.g., for broadcasting).

Definition at line 43 of file session.hpp.

Constructor & Destructor Documentation

◆ ClientSession()

irsol::server::ClientSession::ClientSession ( const irsol::types::client_id_t id,
irsol::types::socket_t &&  sock,
App app 
)

Constructs a new ClientSession.

Parameters
idUnique client identifier (e.g., UUID or socket-derived).
sockAlready-established TCP socket to the client.
appReference to the server application instance.

Definition at line 16 of file session.cpp.

17 : m_id(id), m_socket(std::move(sock)), m_app(app)
18{}
irsol::types::socket_t m_socket
Socket used for communication with the client.
Definition session.hpp:198
irsol::types::client_id_t m_id
Unique ID identifying this session (maps to client_id_t).
Definition session.hpp:195
const App & app() const
Returns a const reference to the owning App instance.
Definition session.hpp:104
App & m_app
Reference to the central App instance for server-wide coordination.
Definition session.hpp:207

Member Function Documentation

◆ app() [1/2]

App & irsol::server::ClientSession::app ( )
inline

Returns a mutable reference to the owning App instance.

Definition at line 110 of file session.hpp.

111 {
112 return m_app;
113 }

◆ app() [2/2]

const App & irsol::server::ClientSession::app ( ) const
inline

Returns a const reference to the owning App instance.

Definition at line 104 of file session.hpp.

105 {
106 return m_app;
107 }

◆ handleOutMessage()

void irsol::server::ClientSession::handleOutMessage ( protocol::OutMessage &&  message)

Handles a single outbound message to the client.

Serializes and sends one message through the socket.

Note
This method is not thread-safe; users must ensure mutual exclusion externally.
See also
irsol::protocol::Serializer
ClientSession::send
Parameters
messageThe message to transmit.

Definition at line 77 of file session.cpp.

78{
79 IRSOL_NAMED_LOG_DEBUG(m_id, "Serializing message: '{}'", irsol::protocol::toString(message));
80 auto serializedMessage = irsol::protocol::Serializer::serialize(std::move(message));
81 IRSOL_NAMED_LOG_DEBUG(m_id, "Serialized message: '{}'", serializedMessage.toString());
82
83 handleSerializedMessage(serializedMessage);
84}
static internal::SerializedMessage serialize(OutMessage &&msg)
Serialize an irsol::protocol::OutMessage variant into a serialized protocol message.
void handleSerializedMessage(const protocol::internal::SerializedMessage &serializedMessage)
Sends an already-serialized message to the client.
Definition session.cpp:87
#define IRSOL_NAMED_LOG_DEBUG(name,...)
Logs a debug-level message using a named logger.
Definition logging.hpp:174
std::string toString(const InMessage &msg)
Converts an incoming message variant to a human-readable string.
Definition variants.cpp:19

◆ handleOutMessages()

void irsol::server::ClientSession::handleOutMessages ( std::vector< protocol::OutMessage > &&  messages)

Handles multiple outbound messages to the client.

Serializes and sends a vector of outbound messages through the socket.

Note
This method is not thread-safe; users must ensure mutual exclusion externally.
See also
irsol::protocol::Serializer
ClientSession::send
Parameters
messagesThe list of messages to transmit.

Definition at line 68 of file session.cpp.

69{
70 IRSOL_NAMED_LOG_DEBUG(m_id, "Serializing {} messages", messages.size());
71 for(auto& message : messages) {
72 handleOutMessage(std::move(message));
73 }
74}
void handleOutMessage(protocol::OutMessage &&message)
Handles a single outbound message to the client.
Definition session.cpp:77

◆ handleSerializedMessage()

void irsol::server::ClientSession::handleSerializedMessage ( const protocol::internal::SerializedMessage serializedMessage)

Sends an already-serialized message to the client.

Note
This method is not thread-safe; users must ensure mutual exclusion externally.
See also
irsol::protocol::Serializer
ClientSession::send
Parameters
serializedMessageMessage that is already serialized to text or binary form.

Definition at line 87 of file session.cpp.

89{
90 // Send the serialized message to the client
91 if(serializedMessage.hasHeader()) {
92 send(serializedMessage.header);
93 }
94 if(serializedMessage.hasPayload()) {
95 send(serializedMessage.payload.data(), serializedMessage.payloadSize());
96 }
97}
void send(const std::string &message)
Sends a text message over the socket to the client.
Definition session.cpp:148

◆ id()

const irsol::types::client_id_t & irsol::server::ClientSession::id ( ) const
inline

Returns the unique client identifier.

Definition at line 116 of file session.hpp.

117 {
118 return m_id;
119 }

◆ processInMessageBuffer()

void irsol::server::ClientSession::processInMessageBuffer ( std::string &  messageBuffer)
private

Processes accumulated raw data into complete protocol messages.

Splits the incoming input buffer into individual protocol messages and dispatches each one for parsing and handling.

Invokes ClientSession::processInRawMessage.

Parameters
messageBufferText buffer containing raw data received from the client's socket.

Definition at line 100 of file session.cpp.

101{
102 size_t newlinePos;
103
104 // Process all complete messages (ending with newline)
105 while((newlinePos = messageBuffer.find('\n')) != std::string::npos) {
106 // Extract the complete message
107 std::string rawMessage = messageBuffer.substr(0, newlinePos);
108
109 // Remove the processed message from the buffer
110 messageBuffer.erase(0, newlinePos + 1);
111
112 // Process the extracted message
113 processInRawMessage(rawMessage);
114 }
115}
void processInRawMessage(const std::string &rawMessage)
Parses and processes a complete incoming raw message.
Definition session.cpp:118

◆ processInRawMessage()

void irsol::server::ClientSession::processInRawMessage ( const std::string &  rawMessage)
private

Parses and processes a complete incoming raw message.

Invokes the registered message handler for the message type.

Parameters
rawMessageComplete raw protocol message string.

Definition at line 118 of file session.cpp.

119{
120 IRSOL_NAMED_LOG_DEBUG(m_id, "Processing raw message: '{}'", rawMessage);
121
122 // Strip the prefix 'bypass ' from the message
123 std::string processedMessage = utils::stripString(rawMessage, "bypass ");
124
125 // Extract the parsed message
126 std::optional<irsol::protocol::InMessage> optionalParsedMessage =
127 irsol::protocol::Parser::parse(processedMessage);
128 if(!optionalParsedMessage) {
129 IRSOL_NAMED_LOG_ERROR(m_id, "Failed to parse message: '{}'", rawMessage);
130 // TODO: ability to create error message without identifier for failed parsing
131 // handleOutMessage(irsol::protocol::Error());
132 return;
133 }
134
135 // Extract the InMessage from the optional wrapper and submit it the the message handler
136 auto result = app().messageHandler().handle(m_id, std::move(*optionalParsedMessage));
137 IRSOL_NAMED_LOG_DEBUG(m_id, "Received {} response(s)", result.size());
138
139 // lock the session's mutex to prevent race conditions
140 std::scoped_lock<std::mutex> lock(m_socketMutex);
141 for(auto& message : result) {
142 handleOutMessage(std::move(message));
143 }
144 IRSOL_NAMED_LOG_DEBUG(m_id, "Sent {} response(s) to client", result.size());
145}
static std::optional< InMessage > parse(const std::string &line)
Attempts to parse a single protocol input line into a structured InMessage.
Definition parser.cpp:11
const handlers::MessageHandler & messageHandler() const
Accessor for the message handler.
Definition app.hpp:114
std::mutex m_socketMutex
Mutex to synchronize socket access from multiple threads.
Definition session.hpp:201
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.
#define IRSOL_NAMED_LOG_ERROR(name,...)
Logs an error-level message using a named logger.
Definition logging.hpp:180
std::string stripString(const std::string &s, const std::string &strippedString)
Removes all occurrences of a specific substring from the start and end of a string.
Definition utils.cpp:89
auto result

◆ run()

void irsol::server::ClientSession::run ( )

Starts the client's session logic.

Initiates the processing loop for the session, including reading incoming messages from the socket and handling disconnections.

Definition at line 21 of file session.cpp.

22{
23 constexpr size_t INITIAL_BUFFER_SIZE = 1024;
24 std::vector<char> buffer(INITIAL_BUFFER_SIZE);
25 std::string messageBuffer;
26
27 IRSOL_NAMED_LOG_DEBUG(m_id, "Client session started running");
28
29 while(true) {
30 // Read data from socket
31 auto readResult = m_socket.read(buffer.data(), buffer.size());
32
33 // Handle read errors or connection closure
34 if(!readResult) {
35 IRSOL_NAMED_LOG_ERROR(m_id, "Socket read error: {}", readResult.error().message());
36 break;
37 }
38
39 size_t bytesRead = readResult.value();
40 if(bytesRead == 0) {
41 IRSOL_NAMED_LOG_INFO(m_id, "Connection closed by client");
42 break;
43 }
44
45 // Append received data to message buffer
46 messageBuffer.append(buffer.data(), bytesRead);
48 m_id,
49 "Read {} bytes: '{}'",
50 bytesRead,
51 messageBuffer.substr(messageBuffer.size() - bytesRead));
52
53 // Process all complete messages in the buffer
54 processInMessageBuffer(messageBuffer);
55
56 // Dynamically resize buffer if it was filled completely
57 if(bytesRead == buffer.size()) {
58 IRSOL_NAMED_LOG_DEBUG(m_id, "Increasing buffer size to {}", buffer.size());
59 buffer.resize(buffer.size() * 2);
60 }
61 }
62
63 m_socket.close();
64 IRSOL_NAMED_LOG_INFO(m_id, "Client session terminated");
65}
void processInMessageBuffer(std::string &messageBuffer)
Processes accumulated raw data into complete protocol messages.
Definition session.cpp:100
#define IRSOL_NAMED_LOG_INFO(name,...)
Logs an info-level message using a named logger.
Definition logging.hpp:176
#define IRSOL_NAMED_LOG_TRACE(name,...)
Logs a trace-level message using a named logger.
Definition logging.hpp:172

◆ send() [1/2]

void irsol::server::ClientSession::send ( const irsol::types::byte_t *const  data,
size_t  size 
)
private

Sends binary data over the socket.

Warning
This function is not thread-safe. Caller must lock m_socketMutex.
Parameters
dataPointer to binary data buffer.
sizeSize of the data in bytes.

Definition at line 169 of file session.cpp.

170{
171 IRSOL_NAMED_LOG_TRACE(m_id, "Sending binary data of size {}", size);
172 if(!m_socket) {
174 m_id, "Socket seems to be closed, this is unexpected. Ignoring send request.");
175 return;
176 }
177
178 auto result = m_socket.write_n(data, size);
179 if(!result) {
180 IRSOL_NAMED_LOG_ERROR(m_id, "Failed to send binary data: {}", result.error().message());
181 } else if(result.value() != size) {
182 IRSOL_NAMED_LOG_WARN(m_id, "Incomplete binary data sent: {} of {} bytes", result.value(), size);
183 }
184}
#define IRSOL_NAMED_LOG_WARN(name,...)
Logs a warning-level message using a named logger.
Definition logging.hpp:178

◆ send() [2/2]

void irsol::server::ClientSession::send ( const std::string &  message)
private

Sends a text message over the socket to the client.

This is the way the server communicates to the client.

Warning
This function is not thread-safe. Caller must lock m_socketMutex.
Parameters
messageThe message string to send.

Definition at line 148 of file session.cpp.

149{
150 std::string preparedMessage = msg;
151
152 IRSOL_NAMED_LOG_TRACE(m_id, "Sending message of size {}", preparedMessage.size());
153 if(!m_socket) {
155 m_id, "Socket seems to be closed, this is unexpected. Ignoring send request.");
156 return;
157 }
158
159 auto result = m_socket.write(preparedMessage);
160 if(!result) {
161 IRSOL_NAMED_LOG_ERROR(m_id, "Failed to send message: {}", result.error().message());
162 } else if(result.value() != preparedMessage.size()) {
164 m_id, "Incomplete message sent: {} of {} bytes", result.value(), preparedMessage.size());
165 }
166}
auto msg

◆ socket() [1/2]

irsol::types::socket_t & irsol::server::ClientSession::socket ( )
inline

Returns a mutable reference to the client socket.

Definition at line 128 of file session.hpp.

129 {
130 return m_socket;
131 }

◆ socket() [2/2]

const irsol::types::socket_t & irsol::server::ClientSession::socket ( ) const
inline

Returns a const reference to the client socket.

Definition at line 122 of file session.hpp.

123 {
124 return m_socket;
125 }

◆ socketMutex()

std::mutex & irsol::server::ClientSession::socketMutex ( )
inline

Returns a reference to the socket mutex used for synchronization.

Definition at line 134 of file session.hpp.

135 {
136 return m_socketMutex;
137 }

◆ userData() [1/2]

irsol::server::internal::UserSessionData & irsol::server::ClientSession::userData ( )
inline

Returns a mutable reference to client-specific session state.

Definition at line 146 of file session.hpp.

147 {
148 return m_sessionData;
149 }
irsol::server::internal::UserSessionData m_sessionData
Session-specific data (e.g., stream rate, frame subscriptions).
Definition session.hpp:204

◆ userData() [2/2]

const irsol::server::internal::UserSessionData & irsol::server::ClientSession::userData ( ) const
inline

Returns a const reference to client-specific session state.

Definition at line 140 of file session.hpp.

141 {
142 return m_sessionData;
143 }

Member Data Documentation

◆ m_app

App& irsol::server::ClientSession::m_app
private

Reference to the central App instance for server-wide coordination.

Definition at line 207 of file session.hpp.

◆ m_id

irsol::types::client_id_t irsol::server::ClientSession::m_id
private

Unique ID identifying this session (maps to client_id_t).

Definition at line 195 of file session.hpp.

◆ m_sessionData

irsol::server::internal::UserSessionData irsol::server::ClientSession::m_sessionData {}
private

Session-specific data (e.g., stream rate, frame subscriptions).

Definition at line 204 of file session.hpp.

204{};

◆ m_socket

irsol::types::socket_t irsol::server::ClientSession::m_socket
private

Socket used for communication with the client.

Definition at line 198 of file session.hpp.

◆ m_socketMutex

std::mutex irsol::server::ClientSession::m_socketMutex {}
private

Mutex to synchronize socket access from multiple threads.

Definition at line 201 of file session.hpp.

201{};

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