Skip to content

Commit 2caae0c

Browse files
authored
refactor(facade): implement HTTP facade with client/server factory methods (#603)
Add simplified HTTP facade following TCP facade pattern. Changes: - Add http_facade.h with client/server configuration structs - Implement http_facade.cpp with factory methods - Add unit tests with 12 test cases (all passing) - Update CMakeLists.txt to build http_facade - Update tests/CMakeLists.txt to build test target Related: - Part of #596 (Create facade classes for protocol families) - Follows pattern from #601 (TCP facade)
1 parent dbbdada commit 2caae0c

5 files changed

Lines changed: 554 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ add_library(NetworkSystem
489489
# Facade layer - simplified protocol creation APIs (Issue #596)
490490
src/facade/tcp_facade.cpp
491491
src/facade/udp_facade.cpp
492+
src/facade/http_facade.cpp
492493

493494
# Basic integration layer - container_integration and messaging_bridge
494495
# (Other integration sources are in network-integration-objects to avoid ODR violations)
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*****************************************************************************
2+
BSD 3-Clause License
3+
4+
Copyright (c) 2024, 🍀☀🌕🌥 🌊
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
10+
1. Redistributions of source code must retain the above copyright notice, this
11+
list of conditions and the following disclaimer.
12+
13+
2. Redistributions in binary form must reproduce the above copyright notice,
14+
this list of conditions and the following disclaimer in the documentation
15+
and/or other materials provided with the distribution.
16+
17+
3. Neither the name of the copyright holder nor the names of its
18+
contributors may be used to endorse or promote products derived from
19+
this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*****************************************************************************/
32+
33+
#pragma once
34+
35+
#include <chrono>
36+
#include <cstdint>
37+
#include <memory>
38+
#include <string>
39+
40+
namespace kcenon::network::core
41+
{
42+
class http_client;
43+
class http_server;
44+
} // namespace kcenon::network::core
45+
46+
namespace kcenon::network::facade
47+
{
48+
49+
/*!
50+
* \class http_facade
51+
* \brief Simplified facade for creating HTTP clients and servers.
52+
*
53+
* This facade provides a simple, unified API for creating HTTP/1.1 protocol
54+
* clients and servers, hiding the complexity of underlying implementation
55+
* from the user.
56+
*
57+
* ### Design Goals
58+
* - **Simplicity**: No template parameters or protocol tags
59+
* - **Consistency**: Same API pattern across all protocol facades
60+
* - **Type Safety**: Returns standard HTTP client/server types
61+
* - **Zero Cost**: No performance overhead compared to direct instantiation
62+
*
63+
* ### Thread Safety
64+
* All methods are thread-safe and can be called concurrently.
65+
*
66+
* ### Usage Example
67+
* \code
68+
* using namespace kcenon::network::facade;
69+
*
70+
* // Create HTTP client
71+
* http_facade facade;
72+
* auto client = facade.create_client({
73+
* .timeout = std::chrono::seconds(10)
74+
* });
75+
*
76+
* // Create HTTP server
77+
* auto server = facade.create_server({
78+
* .port = 8080,
79+
* .server_id = "my-http-server"
80+
* });
81+
* \endcode
82+
*
83+
* \see core::http_client
84+
* \see core::http_server
85+
*/
86+
class http_facade
87+
{
88+
public:
89+
/*!
90+
* \struct client_config
91+
* \brief Configuration for creating an HTTP client.
92+
*/
93+
struct client_config
94+
{
95+
//! Request timeout
96+
std::chrono::milliseconds timeout = std::chrono::seconds(30);
97+
};
98+
99+
/*!
100+
* \struct server_config
101+
* \brief Configuration for creating an HTTP server.
102+
*/
103+
struct server_config
104+
{
105+
//! Port number to listen on
106+
uint16_t port = 0;
107+
108+
//! Server identifier (optional, auto-generated if not provided)
109+
std::string server_id;
110+
};
111+
112+
/*!
113+
* \brief Creates an HTTP client with the specified configuration.
114+
* \param config Client configuration.
115+
* \return Shared pointer to http_client.
116+
* \throws std::invalid_argument if configuration is invalid.
117+
*
118+
* ### Behavior
119+
* - Creates an http_client instance with the specified timeout
120+
* - Default timeout is 30 seconds if not specified
121+
*
122+
* ### Error Conditions
123+
* - Throws if timeout is zero or negative
124+
*/
125+
[[nodiscard]] auto create_client(const client_config& config) const
126+
-> std::shared_ptr<core::http_client>;
127+
128+
/*!
129+
* \brief Creates an HTTP server with the specified configuration.
130+
* \param config Server configuration.
131+
* \return Shared pointer to http_server.
132+
* \throws std::invalid_argument if configuration is invalid.
133+
*
134+
* ### Behavior
135+
* - Creates an http_server instance
136+
* - Server ID is auto-generated if not provided
137+
* - Server must be started manually using start() method
138+
*
139+
* ### Error Conditions
140+
* - Throws if port is 0 or > 65535
141+
*/
142+
[[nodiscard]] auto create_server(const server_config& config) const
143+
-> std::shared_ptr<core::http_server>;
144+
145+
private:
146+
//! \brief Generates a unique server ID
147+
[[nodiscard]] static auto generate_server_id() -> std::string;
148+
149+
//! \brief Validates client configuration
150+
static auto validate_client_config(const client_config& config) -> void;
151+
152+
//! \brief Validates server configuration
153+
static auto validate_server_config(const server_config& config) -> void;
154+
};
155+
156+
} // namespace kcenon::network::facade

src/facade/http_facade.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*****************************************************************************
2+
BSD 3-Clause License
3+
4+
Copyright (c) 2024, 🍀☀🌕🌥 🌊
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
10+
1. Redistributions of source code must retain the above copyright notice, this
11+
list of conditions and the following disclaimer.
12+
13+
2. Redistributions in binary form must reproduce the above copyright notice,
14+
this list of conditions and the following disclaimer in the documentation
15+
and/or other materials provided with the distribution.
16+
17+
3. Neither the name of the copyright holder nor the names of its
18+
contributors may be used to endorse or promote products derived from
19+
this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*****************************************************************************/
32+
33+
#include "kcenon/network/facade/http_facade.h"
34+
35+
#include <atomic>
36+
#include <iomanip>
37+
#include <sstream>
38+
#include <stdexcept>
39+
40+
#include "kcenon/network/http/http_client.h"
41+
#include "kcenon/network/http/http_server.h"
42+
43+
namespace kcenon::network::facade
44+
{
45+
46+
namespace
47+
{
48+
//! \brief Atomic counter for generating unique server IDs
49+
std::atomic<uint64_t> g_server_id_counter{0};
50+
} // namespace
51+
52+
auto http_facade::generate_server_id() -> std::string
53+
{
54+
const auto id = g_server_id_counter.fetch_add(1, std::memory_order_relaxed);
55+
std::ostringstream oss;
56+
oss << "http_server_" << std::setfill('0') << std::setw(8) << id;
57+
return oss.str();
58+
}
59+
60+
auto http_facade::validate_client_config(const client_config& config) -> void
61+
{
62+
if (config.timeout.count() <= 0)
63+
{
64+
throw std::invalid_argument("http_facade: timeout must be positive");
65+
}
66+
}
67+
68+
auto http_facade::validate_server_config(const server_config& config) -> void
69+
{
70+
if (config.port == 0 || config.port > 65535)
71+
{
72+
throw std::invalid_argument("http_facade: port must be between 1 and 65535");
73+
}
74+
}
75+
76+
auto http_facade::create_client(const client_config& config) const
77+
-> std::shared_ptr<core::http_client>
78+
{
79+
validate_client_config(config);
80+
81+
return std::make_shared<core::http_client>(config.timeout);
82+
}
83+
84+
auto http_facade::create_server(const server_config& config) const
85+
-> std::shared_ptr<core::http_server>
86+
{
87+
validate_server_config(config);
88+
89+
const auto server_id = config.server_id.empty() ? generate_server_id() : config.server_id;
90+
91+
return std::make_shared<core::http_server>(server_id);
92+
}
93+
94+
} // namespace kcenon::network::facade

tests/CMakeLists.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,39 @@ network_gtest_discover_tests(network_udp_facade_test
22112211

22122212
message(STATUS "UDP facade tests enabled")
22132213

2214+
# HTTP facade tests
2215+
add_executable(network_http_facade_test
2216+
test_http_facade.cpp
2217+
)
2218+
2219+
target_link_libraries(network_http_facade_test PRIVATE
2220+
NetworkSystem
2221+
GTest::gtest
2222+
GTest::gtest_main
2223+
Threads::Threads
2224+
)
2225+
2226+
# Setup ASIO integration
2227+
setup_asio_integration(network_http_facade_test)
2228+
2229+
# Add system integration paths if available
2230+
if(COMMON_SYSTEM_INCLUDE_DIR)
2231+
target_include_directories(network_http_facade_test PRIVATE ${COMMON_SYSTEM_INCLUDE_DIR})
2232+
target_compile_definitions(network_http_facade_test PRIVATE WITH_COMMON_SYSTEM)
2233+
endif()
2234+
2235+
set_target_properties(network_http_facade_test PROPERTIES
2236+
CXX_STANDARD 20
2237+
CXX_STANDARD_REQUIRED ON
2238+
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
2239+
)
2240+
2241+
network_gtest_discover_tests(network_http_facade_test
2242+
DISCOVERY_TIMEOUT 60
2243+
)
2244+
2245+
message(STATUS "HTTP facade tests enabled")
2246+
22142247
##################################################
22152248
# Integration Tests
22162249
##################################################

0 commit comments

Comments
 (0)