This commit is contained in:
2025-09-15 10:28:17 -04:00
parent ec2ad27e33
commit 1b220d0d1c
8 changed files with 479 additions and 193 deletions

View File

@@ -30,28 +30,26 @@ struct Server;
*/
struct MessageSender {
/**
* @brief Append message data to connection's outgoing message queue.
* @brief Send response with protocol-specific context for ordering.
*
* Thread-safe method that can be called from any thread, including
* pipeline processing threads. The arena is moved into the connection
* to maintain data lifetime until the message is sent. Messages appended
* concurrently may be written in either order, but they will not be
* interleaved.
* Thread-safe method for pipeline threads to send responses back to clients.
* Delegates to the connection's protocol handler for ordering logic.
* The protocol handler may queue the response or send it immediately.
*
* @param data_parts Span of string_view parts to send (arena-allocated)
* @param arena Arena containing the memory for data_parts string_views
* @param close_after_send Whether to close connection after sending
* @param protocol_context Arena-allocated protocol-specific context
* @param data Response data parts (may be empty for deferred serialization)
* @param arena Arena containing response data and context
*
* Example usage:
* ```cpp
* auto response_parts = arena.allocate_span<std::string_view>(2);
* response_parts[0] = "HTTP/1.1 200 OK\r\n\r\n";
* response_parts[1] = "Hello World";
* conn.append_message(response_parts, std::move(arena));
* auto* ctx = arena.allocate<HttpResponseContext>();
* ctx->sequence_id = 42;
* auto response_data = format_response(arena);
* conn.send_response(ctx, response_data, std::move(arena));
* ```
*/
virtual void append_message(std::span<std::string_view> data_parts,
Arena arena, bool close_after_send = false) = 0;
virtual void send_response(void *protocol_context,
std::string_view response_json, Arena arena) = 0;
virtual ~MessageSender() = default;
};
@@ -104,31 +102,33 @@ struct Connection : MessageSender {
* @brief Queue an atomic message to be sent to the client.
*
* Adds a complete message with all associated data to the connection's
* outgoing message queue. The message will be sent asynchronously by a
* server I/O thread using efficient vectored I/O.
* outgoing byte queue with guaranteed ordering.
*
* I/O thread only method for protocol handlers to queue bytes for sending.
* Bytes are queued in order and sent using efficient vectored I/O.
*
* @param data_parts Span of string_views pointing to arena-allocated data
* @param arena Arena that owns all the memory referenced by data_parts
* @param close_after_send Whether to close connection after sending this
* message
*
* @note Thread Safety: This method is thread-safe and can be called
* concurrently from multiple pipeline threads.
* @param close_after_send Whether to close connection after sending
*
* @note Thread Safety: Must be called from I/O thread only.
* @note Ordering: Bytes are sent in the order calls are made.
* @note The memory referenced by the data_parts span, must outlive @p arena.
* The arena will be moved and kept alive until the message is fully sent.
*
* Example usage:
* Example usage (from ConnectionHandler::on_preprocess_writes):
* ```cpp
* Arena arena;
* auto parts = arena.allocate_span<std::string_view>(2);
* parts[0] = build_header(arena);
* parts[1] = build_body(arena);
* conn.append_message({parts, 2}, std::move(arena));
* conn.append_bytes({parts, 2}, std::move(arena), false);
* ```
*/
void append_message(std::span<std::string_view> data_parts, Arena arena,
bool close_after_send) override;
void append_bytes(std::span<std::string_view> data_parts, Arena arena,
bool close_after_send);
void send_response(void *protocol_context, std::string_view response_json,
Arena arena) override;
/**
* @brief Get a WeakRef to this connection for async operations.
@@ -342,6 +342,10 @@ private:
// mutex_, but if non-empty mutex_ can be
// dropped while server accesses existing elements.
int64_t outgoing_bytes_queued_{0}; // Counter of queued bytes
bool has_pending_responses_{
false}; // True if protocol handler has responses to process
std::deque<PendingResponse>
pending_response_queue_; // Responses awaiting protocol processing
// Set to a negative number in `close`
int fd_;