Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
http_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#include <sstream>
12
16
18
19// =========================================================================
20// http_request_session implementation
21// =========================================================================
22
24 std::string_view session_id,
25 std::string_view client_address,
26 uint16_t client_port,
27 std::weak_ptr<core::http_server> server)
28 : session_id_(session_id)
29 , client_address_(client_address)
30 , client_port_(client_port)
31 , server_(std::move(server))
32{
33}
34
35auto http_request_session::id() const -> std::string_view
36{
37 return session_id_;
38}
39
41{
42 return is_connected_.load(std::memory_order_acquire);
43}
44
45auto http_request_session::send(std::vector<uint8_t>&& data) -> VoidResult
46{
47 if (!is_connected_.load(std::memory_order_acquire))
48 {
49 return error_void(
51 "Session is not connected",
52 "http_request_session::send"
53 );
54 }
55
56 std::lock_guard<std::mutex> lock(data_mutex_);
57 response_data_ = std::move(data);
58
59 return ok();
60}
61
63{
64 is_connected_.store(false, std::memory_order_release);
65}
66
67auto http_request_session::set_response_data(std::vector<uint8_t> data) -> void
68{
69 std::lock_guard<std::mutex> lock(data_mutex_);
70 response_data_ = std::move(data);
71}
72
73auto http_request_session::get_response_data() const -> const std::vector<uint8_t>&
74{
75 std::lock_guard<std::mutex> lock(data_mutex_);
76 return response_data_;
77}
78
79// =========================================================================
80// http_server_adapter implementation
81// =========================================================================
82
84 : server_id_(server_id)
85 , server_(std::make_shared<core::http_server>(std::string(server_id)))
86{
88}
89
91{
92 if (server_ && is_running_.load(std::memory_order_acquire))
93 {
94 (void)server_->stop();
95 }
96}
97
98// =========================================================================
99// i_network_component interface implementation
100// =========================================================================
101
103{
104 return is_running_.load(std::memory_order_acquire);
105}
106
108{
109 if (server_)
110 {
111 server_->wait_for_stop();
112 }
113}
114
115// =========================================================================
116// i_protocol_server interface implementation
117// =========================================================================
118
120{
121 if (!server_)
122 {
123 return error_void(
125 "Server not initialized",
126 "http_server_adapter::start"
127 );
128 }
129
130 auto result = server_->start(port);
131 if (result.is_ok())
132 {
133 is_running_.store(true, std::memory_order_release);
134 }
135 return result;
136}
137
139{
140 if (!server_)
141 {
142 return error_void(
144 "Server not initialized",
145 "http_server_adapter::stop"
146 );
147 }
148
149 auto result = server_->stop();
150 is_running_.store(false, std::memory_order_release);
151
152 // Clear tracked sessions on stop
153 {
154 std::lock_guard<std::mutex> lock(sessions_mutex_);
155 sessions_.clear();
156 }
157
158 return result;
159}
160
162{
163 std::lock_guard<std::mutex> lock(sessions_mutex_);
164 return sessions_.size();
165}
166
168{
169 std::lock_guard<std::mutex> lock(callbacks_mutex_);
170 connection_callback_ = std::move(callback);
171}
172
174{
175 std::lock_guard<std::mutex> lock(callbacks_mutex_);
176 disconnection_callback_ = std::move(callback);
177}
178
180{
181 std::lock_guard<std::mutex> lock(callbacks_mutex_);
182 receive_callback_ = std::move(callback);
183}
184
186{
187 std::lock_guard<std::mutex> lock(callbacks_mutex_);
188 error_callback_ = std::move(callback);
189}
190
191// =========================================================================
192// Internal methods
193// =========================================================================
194
196{
197 if (!server_)
198 {
199 return;
200 }
201
202 // Register a catch-all POST handler for unified protocol interface
203 // The i_protocol_client.send() performs HTTP POST, so we handle POST requests
204 server_->post("/:path", [this](const core::http_request_context& ctx) {
205 // Create a session for this request
206 const auto request_id = request_counter_.fetch_add(1, std::memory_order_relaxed);
207 const auto session_id = make_session_id("client", 0, request_id);
208 auto session = std::make_shared<http_request_session>(
209 session_id, "client", 0, server_);
210
211 // Track the session
212 {
213 std::lock_guard<std::mutex> lock(sessions_mutex_);
214 sessions_[session_id] = session;
215 }
216
217 // Notify connection callback
218 {
219 connection_callback_t callback_copy;
220 {
221 std::lock_guard<std::mutex> lock(callbacks_mutex_);
222 callback_copy = connection_callback_;
223 }
224 if (callback_copy)
225 {
226 callback_copy(session);
227 }
228 }
229
230 // Notify receive callback with request body
231 {
232 receive_callback_t callback_copy;
233 {
234 std::lock_guard<std::mutex> lock(callbacks_mutex_);
235 callback_copy = receive_callback_;
236 }
237 if (callback_copy)
238 {
239 callback_copy(session_id, ctx.request.body);
240 }
241 }
242
243 // Build response from session data
245 response.status_code = 200;
246 response.body = session->get_response_data();
247 response.set_header("Content-Type", "application/octet-stream");
248
249 // Notify disconnection callback
250 {
251 disconnection_callback_t callback_copy;
252 {
253 std::lock_guard<std::mutex> lock(callbacks_mutex_);
254 callback_copy = disconnection_callback_;
255 }
256 if (callback_copy)
257 {
258 callback_copy(session_id);
259 }
260 }
261
262 // Remove session
263 remove_session(session_id);
264
265 return response;
266 });
267
268 // Also register root POST handler
269 server_->post("/", [this](const core::http_request_context& ctx) {
270 const auto request_id = request_counter_.fetch_add(1, std::memory_order_relaxed);
271 const auto session_id = make_session_id("client", 0, request_id);
272 auto session = std::make_shared<http_request_session>(
273 session_id, "client", 0, server_);
274
275 {
276 std::lock_guard<std::mutex> lock(sessions_mutex_);
277 sessions_[session_id] = session;
278 }
279
280 {
281 connection_callback_t callback_copy;
282 {
283 std::lock_guard<std::mutex> lock(callbacks_mutex_);
284 callback_copy = connection_callback_;
285 }
286 if (callback_copy)
287 {
288 callback_copy(session);
289 }
290 }
291
292 {
293 receive_callback_t callback_copy;
294 {
295 std::lock_guard<std::mutex> lock(callbacks_mutex_);
296 callback_copy = receive_callback_;
297 }
298 if (callback_copy)
299 {
300 callback_copy(session_id, ctx.request.body);
301 }
302 }
303
305 response.status_code = 200;
306 response.body = session->get_response_data();
307 response.set_header("Content-Type", "application/octet-stream");
308
309 {
310 disconnection_callback_t callback_copy;
311 {
312 std::lock_guard<std::mutex> lock(callbacks_mutex_);
313 callback_copy = disconnection_callback_;
314 }
315 if (callback_copy)
316 {
317 callback_copy(session_id);
318 }
319 }
320
321 remove_session(session_id);
322
323 return response;
324 });
325}
326
328 const std::string& address,
329 uint16_t port,
330 uint64_t request_id) -> std::string
331{
332 std::ostringstream oss;
333 oss << address << ":" << port << "#" << request_id;
334 return oss.str();
335}
336
338 const std::string& address,
339 uint16_t port) -> std::shared_ptr<http_request_session>
340{
341 const auto request_id = request_counter_.fetch_add(1, std::memory_order_relaxed);
342 const auto session_id = make_session_id(address, port, request_id);
343
344 std::lock_guard<std::mutex> lock(sessions_mutex_);
345
346 auto session = std::make_shared<http_request_session>(
347 session_id, address, port, server_);
348 sessions_[session_id] = session;
349
350 return session;
351}
352
353auto http_server_adapter::remove_session(const std::string& session_id) -> void
354{
355 std::lock_guard<std::mutex> lock(sessions_mutex_);
356 sessions_.erase(session_id);
357}
358
359} // 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.
auto is_connected() const -> bool override
Checks if the session is currently connected.
http_request_session(std::string_view session_id, std::string_view client_address, uint16_t client_port, std::weak_ptr< core::http_server > server)
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.
auto get_response_data() const -> const std::vector< uint8_t > &
Gets the stored response data.
auto set_response_data(std::vector< uint8_t > data) -> void
Stores the response data to be sent back to client.
std::unordered_map< std::string, std::shared_ptr< http_request_session > > sessions_
auto wait_for_stop() -> void override
Blocks until the component has stopped.
http_server_adapter(std::string_view server_id)
Constructs an adapter with a unique server ID.
~http_server_adapter() override
Destructor ensures proper cleanup.
auto set_connection_callback(connection_callback_t callback) -> void override
Sets the callback for new connections.
auto is_running() const -> bool override
Checks if the component is currently running.
auto setup_internal_routes() -> void
Sets up internal HTTP routes to bridge to i_protocol_server callbacks.
auto remove_session(const std::string &session_id) -> void
Removes a session after request processing.
static auto make_session_id(const std::string &address, uint16_t port, uint64_t request_id) -> std::string
Creates a unique session ID from request info.
auto set_disconnection_callback(disconnection_callback_t callback) -> void override
Sets the callback for disconnections.
auto get_or_create_session(const std::string &address, uint16_t port) -> std::shared_ptr< http_request_session >
Gets or creates a session for the given request.
auto set_error_callback(error_callback_t callback) -> void override
Sets the callback for errors.
auto set_receive_callback(receive_callback_t callback) -> void override
Sets the callback for received data.
auto stop() -> VoidResult override
Stops the server and closes all connections.
auto connection_count() const -> size_t override
Gets the number of active client connections.
auto start(uint16_t port) -> VoidResult override
Starts the server and begins listening for connections.
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
VoidResult ok()
Network-specific error and result type definitions.
Context for an HTTP request with parsed components.
Definition http_server.h:71
Represents an HTTP response message.
Definition http_types.h:162
auto set_header(const std::string &name, const std::string &value) -> void
Set a header value.