Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
ws_server_adapter.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
6
8
10
11// =========================================================================
12// ws_session_wrapper implementation
13// =========================================================================
14
15ws_session_wrapper::ws_session_wrapper(std::shared_ptr<core::ws_connection> connection)
16 : connection_(std::move(connection))
17{
18 // Cache the ID since it may be accessed frequently
19 if (connection_)
20 {
21 id_cache_ = std::string(connection_->id());
22 }
23}
24
25auto ws_session_wrapper::id() const -> std::string_view
26{
27 return id_cache_;
28}
29
31{
32 return connection_ && connection_->is_connected();
33}
34
35auto ws_session_wrapper::send(std::vector<uint8_t>&& data) -> VoidResult
36{
37 if (!connection_)
38 {
39 return error_void(
41 "Connection no longer available",
42 "ws_session_wrapper::send"
43 );
44 }
45
46 // Send as binary WebSocket frame
47 return connection_->send_binary(std::move(data));
48}
49
51{
52 if (connection_)
53 {
54 connection_->close();
55 }
56}
57
58// =========================================================================
59// ws_server_adapter implementation
60// =========================================================================
61
62ws_server_adapter::ws_server_adapter(std::string_view server_id)
63 : server_id_(server_id)
64 , server_(std::make_shared<core::messaging_ws_server>(std::string(server_id)))
65{
67}
68
70{
71 if (server_ && server_->is_running())
72 {
73 (void)server_->stop();
74 }
75}
76
77// =========================================================================
78// Path Configuration
79// =========================================================================
80
81auto ws_server_adapter::set_path(std::string_view path) -> void
82{
83 path_ = std::string(path);
84}
85
86// =========================================================================
87// i_network_component interface implementation
88// =========================================================================
89
91{
92 return server_ && server_->is_running();
93}
94
96{
97 if (server_)
98 {
99 server_->wait_for_stop();
100 }
101}
102
103// =========================================================================
104// i_protocol_server interface implementation
105// =========================================================================
106
108{
109 if (!server_)
110 {
111 return error_void(
113 "Server not initialized",
114 "ws_server_adapter::start"
115 );
116 }
117
118 // Use the stored path (set via set_path, or default "/")
119 return server_->start_server(port, path_);
120}
121
123{
124 if (!server_)
125 {
126 return error_void(
128 "Server not initialized",
129 "ws_server_adapter::stop"
130 );
131 }
132
133 auto result = server_->stop();
134
135 // Clear tracked sessions on stop
136 {
137 std::lock_guard<std::mutex> lock(sessions_mutex_);
138 sessions_.clear();
139 }
140
141 return result;
142}
143
145{
146 return server_ ? server_->connection_count() : 0;
147}
148
150{
151 std::lock_guard<std::mutex> lock(callbacks_mutex_);
152 connection_callback_ = std::move(callback);
153}
154
156{
157 std::lock_guard<std::mutex> lock(callbacks_mutex_);
158 disconnection_callback_ = std::move(callback);
159}
160
162{
163 std::lock_guard<std::mutex> lock(callbacks_mutex_);
164 receive_callback_ = std::move(callback);
165}
166
168{
169 std::lock_guard<std::mutex> lock(callbacks_mutex_);
170 error_callback_ = std::move(callback);
171}
172
173// =========================================================================
174// Internal methods
175// =========================================================================
176
178{
179 if (!server_)
180 {
181 return;
182 }
183
184 // Bridge WebSocket connection callback
185 server_->set_connection_callback(
186 [this](std::shared_ptr<interfaces::i_websocket_session> ws_session)
187 {
188 // Cast to ws_connection for our wrapper
189 auto ws_conn = std::dynamic_pointer_cast<core::ws_connection>(ws_session);
190 if (!ws_conn)
191 {
192 return;
193 }
194
195 auto session = get_or_create_session(ws_conn);
196
197 connection_callback_t callback_copy;
198 {
199 std::lock_guard<std::mutex> lock(callbacks_mutex_);
200 callback_copy = connection_callback_;
201 }
202
203 if (callback_copy)
204 {
205 callback_copy(session);
206 }
207 });
208
209 // Bridge WebSocket disconnection callback (ignore close code and reason)
210 server_->set_disconnection_callback(
211 [this](std::string_view session_id, uint16_t /* code */, std::string_view /* reason */)
212 {
213 // Remove from tracked sessions
214 {
215 std::lock_guard<std::mutex> lock(sessions_mutex_);
216 sessions_.erase(std::string(session_id));
217 }
218
219 disconnection_callback_t callback_copy;
220 {
221 std::lock_guard<std::mutex> lock(callbacks_mutex_);
222 callback_copy = disconnection_callback_;
223 }
224
225 if (callback_copy)
226 {
227 callback_copy(session_id);
228 }
229 });
230
231 // Bridge WebSocket binary message callback
232 server_->set_binary_callback(
233 [this](std::string_view session_id, const std::vector<uint8_t>& data)
234 {
235 receive_callback_t callback_copy;
236 {
237 std::lock_guard<std::mutex> lock(callbacks_mutex_);
238 callback_copy = receive_callback_;
239 }
240
241 if (callback_copy)
242 {
243 callback_copy(session_id, data);
244 }
245 });
246
247 // Bridge WebSocket error callback
248 server_->set_error_callback(
249 [this](std::string_view session_id, std::error_code ec)
250 {
251 error_callback_t callback_copy;
252 {
253 std::lock_guard<std::mutex> lock(callbacks_mutex_);
254 callback_copy = error_callback_;
255 }
256
257 if (callback_copy)
258 {
259 callback_copy(session_id, ec);
260 }
261 });
262}
263
264auto ws_server_adapter::get_or_create_session(std::shared_ptr<core::ws_connection> connection)
265 -> std::shared_ptr<interfaces::i_session>
266{
267 std::string session_id(connection->id());
268
269 std::lock_guard<std::mutex> lock(sessions_mutex_);
270
271 auto it = sessions_.find(session_id);
272 if (it != sessions_.end())
273 {
274 return it->second;
275 }
276
277 // Create new session wrapper
278 auto session = std::make_shared<ws_session_wrapper>(connection);
279 sessions_[session_id] = session;
280
281 return session;
282}
283
284} // namespace kcenon::network::internal::adapters
std::function< void(std::string_view)> disconnection_callback_t
Callback type for disconnections (session_id)
std::function< void(std::string_view, const std::vector< uint8_t > &)> receive_callback_t
Callback type for received data (session_id, data)
std::function< void(std::string_view, std::error_code)> error_callback_t
Callback type for errors (session_id, error)
std::function< void(std::shared_ptr< i_session >)> connection_callback_t
Callback type for new connections.
std::shared_ptr< core::messaging_ws_server > server_
auto get_or_create_session(std::shared_ptr< core::ws_connection > connection) -> std::shared_ptr< interfaces::i_session >
Gets or creates a session wrapper for the given connection.
~ws_server_adapter() override
Destructor ensures proper cleanup.
auto set_connection_callback(connection_callback_t callback) -> void override
Sets the callback for new connections.
auto set_receive_callback(receive_callback_t callback) -> void override
Sets the callback for received data.
auto is_running() const -> bool override
Checks if the component is currently running.
auto set_path(std::string_view path) -> void
Sets the WebSocket path for accepting connections.
auto set_disconnection_callback(disconnection_callback_t callback) -> void override
Sets the callback for disconnections.
auto connection_count() const -> size_t override
Gets the number of active client connections.
auto setup_internal_callbacks() -> void
Sets up internal callbacks to bridge WebSocket callbacks to i_protocol_server callbacks.
auto set_error_callback(error_callback_t callback) -> void override
Sets the callback for errors.
auto stop() -> VoidResult override
Stops the server and closes all connections.
auto start(uint16_t port) -> VoidResult override
Starts the server and begins listening for connections.
auto wait_for_stop() -> void override
Blocks until the component has stopped.
ws_server_adapter(std::string_view server_id)
Constructs an adapter with a unique server ID.
auto close() -> void override
Closes the session.
auto is_connected() const -> bool override
Checks if the session is currently connected.
std::shared_ptr< core::ws_connection > connection_
auto send(std::vector< uint8_t > &&data) -> VoidResult override
Sends data to the client.
auto id() const -> std::string_view override
Gets the unique identifier for this session.
ws_session_wrapper(std::shared_ptr< core::ws_connection > connection)
QUIC connection state machine (RFC 9000 Section 5)
Definition connection.h:158
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")