Branch data Line data Source code
1 : : /*
2 : : * Copyright 2025 Jinwoo Sung
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include "wirestead/builder/tcp_server_builder.hpp"
18 : :
19 : : #include <boost/asio/io_context.hpp>
20 : :
21 : : #include "wirestead/builder/auto_initializer.hpp"
22 : : #include "wirestead/diagnostics/exceptions.hpp"
23 : :
24 : : namespace wirestead {
25 : : namespace builder {
26 : :
27 : 97 : TcpServerBuilder::TcpServerBuilder(uint16_t port)
28 : 97 : : port_(port),
29 : 97 : bind_address_("0.0.0.0"),
30 : 97 : auto_start_(false),
31 : 97 : independent_context_(false),
32 : 97 : shared_context_(false),
33 : 97 : max_clients_(0),
34 : 97 : client_limit_enabled_(false),
35 : 97 : port_retry_enabled_(false),
36 : 97 : max_port_retries_(3),
37 : 97 : port_retry_interval_ms_(1000),
38 : 194 : idle_timeout_(0),
39 : 97 : idle_timeout_set_(false),
40 : 97 : tcp_no_delay_(true),
41 : 97 : keep_alive_(false),
42 : 97 : send_buffer_size_(0),
43 : 97 : receive_buffer_size_(0),
44 : 194 : read_buffer_size_(base::constants::DEFAULT_READ_BUFFER_SIZE) {
45 [ + + + - : 109 : if (port == 0) throw diagnostics::BuilderException("Invalid port number: 0");
+ - + - +
- ]
46 : :
47 : : // Ensure background IO service is running
48 : 95 : AutoInitializer::ensure_io_context_running();
49 : 103 : }
50 : :
51 : 95 : std::unique_ptr<wrapper::TcpServer> TcpServerBuilder::build() {
52 : 95 : std::unique_ptr<wrapper::TcpServer> server;
53 [ + + ]: 95 : if (independent_context_) {
54 : 1 : server = std::make_unique<wrapper::TcpServer>(port_, std::make_shared<boost::asio::io_context>());
55 : 1 : server->manage_external_context(true);
56 : : } else {
57 : 94 : server = std::make_unique<wrapper::TcpServer>(port_);
58 : : }
59 [ + + + - ]: 95 : if (shared_context_) server->shared_context(true);
60 : :
61 [ + + + - : 95 : if (this->on_data_) server->on_data(this->on_data_);
+ - ]
62 [ + + + - : 95 : if (this->on_data_batch_) server->on_data_batch(this->on_data_batch_);
+ - ]
63 [ + + + - : 95 : if (this->on_connect_) server->on_connect(this->on_connect_);
+ - ]
64 [ + + + - : 95 : if (this->on_disconnect_) server->on_disconnect(this->on_disconnect_);
+ - ]
65 [ + + + - : 95 : if (this->on_error_) server->on_error(this->on_error_);
+ - ]
66 [ + + + - : 95 : if (this->on_backpressure_) server->on_backpressure(this->on_backpressure_);
+ - ]
67 : :
68 [ + + ]: 95 : if (client_limit_enabled_) {
69 : 13 : server->max_clients(max_clients_);
70 : : }
71 : :
72 [ + + + - ]: 95 : if (bind_address_set_) server->bind_address(bind_address_);
73 [ + + + - : 95 : if (port_retry_enabled_set_ || max_port_retries_set_ || port_retry_interval_set_) {
- + ]
74 : 4 : server->port_retry(port_retry_enabled_, static_cast<int>(max_port_retries_),
75 : 4 : static_cast<int>(port_retry_interval_ms_));
76 : : }
77 [ + + + - ]: 95 : if (idle_timeout_set_) server->idle_timeout(idle_timeout_);
78 [ + + + - ]: 95 : if (tcp_no_delay_set_) server->tcp_no_delay(tcp_no_delay_);
79 [ + + + - ]: 95 : if (keep_alive_set_) server->keep_alive(keep_alive_);
80 [ + - - + : 95 : if (!tls_certificate_file_.empty() || !tls_private_key_file_.empty())
- + ]
81 : 0 : server->tls(tls_certificate_file_, tls_private_key_file_);
82 [ + + + - ]: 95 : if (send_buffer_size_set_) server->send_buffer_size(send_buffer_size_);
83 [ + + + - ]: 95 : if (receive_buffer_size_set_) server->receive_buffer_size(receive_buffer_size_);
84 [ + + + - ]: 95 : if (read_buffer_size_set_) server->read_buffer_size(read_buffer_size_);
85 : :
86 [ + + + - ]: 95 : if (this->bp_strategy_set_) server->backpressure_strategy(this->bp_strategy_);
87 : 95 : server->backpressure_threshold(this->get_effective_backpressure_threshold());
88 : :
89 [ + + ]: 95 : if (this->framer_factory_) {
90 : 2 : server->framer(this->framer_factory_);
91 : : }
92 [ + + ]: 95 : if (this->on_message_) {
93 : 2 : server->on_message(this->on_message_);
94 : : }
95 [ + + ]: 95 : if (this->on_message_batch_) {
96 : 1 : server->on_message_batch(this->on_message_batch_);
97 : : }
98 : :
99 [ + + ]: 95 : if (auto_start_) {
100 : 1 : server->auto_start(true);
101 : : }
102 : :
103 : 95 : return server;
104 : 0 : }
105 : :
106 : 2 : TcpServerBuilder& TcpServerBuilder::auto_start(bool auto_start) {
107 : 2 : auto_start_ = auto_start;
108 : 2 : return *this;
109 : : }
110 : :
111 : 1 : TcpServerBuilder& TcpServerBuilder::bind_address(const std::string& address) {
112 : 1 : bind_address_ = address;
113 : 1 : bind_address_set_ = true;
114 : 1 : return *this;
115 : : }
116 : :
117 : 2 : TcpServerBuilder& TcpServerBuilder::independent_context(bool use_independent) {
118 : 2 : independent_context_ = use_independent;
119 : 2 : return *this;
120 : : }
121 : :
122 : 2 : TcpServerBuilder& TcpServerBuilder::shared_context(bool use_shared) {
123 : 2 : shared_context_ = use_shared;
124 : 2 : return *this;
125 : : }
126 : :
127 : 11 : TcpServerBuilder& TcpServerBuilder::max_clients(uint32_t max_clients) {
128 : 11 : max_clients_ = max_clients;
129 : 11 : client_limit_enabled_ = true;
130 : 11 : return *this;
131 : : }
132 : :
133 : 1 : TcpServerBuilder& TcpServerBuilder::enable_port_retry(bool enable) {
134 : 1 : port_retry_enabled_ = enable;
135 : 1 : port_retry_enabled_set_ = true;
136 : 1 : return *this;
137 : : }
138 : :
139 : 1 : TcpServerBuilder& TcpServerBuilder::max_port_retries(uint32_t max_retries) {
140 : 1 : max_port_retries_ = max_retries;
141 : 1 : max_port_retries_set_ = true;
142 : 1 : return *this;
143 : : }
144 : :
145 : 1 : TcpServerBuilder& TcpServerBuilder::port_retry_interval(std::chrono::milliseconds interval) {
146 : 1 : port_retry_interval_ms_ = static_cast<uint32_t>(interval.count());
147 : 1 : port_retry_interval_set_ = true;
148 : 1 : return *this;
149 : : }
150 : :
151 : 1 : TcpServerBuilder& TcpServerBuilder::tcp_no_delay(bool enable) {
152 : 1 : tcp_no_delay_ = enable;
153 : 1 : tcp_no_delay_set_ = true;
154 : 1 : return *this;
155 : : }
156 : :
157 : 1 : TcpServerBuilder& TcpServerBuilder::keep_alive(bool enable) {
158 : 1 : keep_alive_ = enable;
159 : 1 : keep_alive_set_ = true;
160 : 1 : return *this;
161 : : }
162 : :
163 : 0 : TcpServerBuilder& TcpServerBuilder::tls(const std::string& certificate_file, const std::string& private_key_file) {
164 : 0 : tls_certificate_file_ = certificate_file;
165 : 0 : tls_private_key_file_ = private_key_file;
166 : 0 : return *this;
167 : : }
168 : :
169 : 1 : TcpServerBuilder& TcpServerBuilder::send_buffer_size(size_t bytes) {
170 : 1 : send_buffer_size_ = bytes;
171 : 1 : send_buffer_size_set_ = true;
172 : 1 : return *this;
173 : : }
174 : :
175 : 1 : TcpServerBuilder& TcpServerBuilder::receive_buffer_size(size_t bytes) {
176 : 1 : receive_buffer_size_ = bytes;
177 : 1 : receive_buffer_size_set_ = true;
178 : 1 : return *this;
179 : : }
180 : :
181 : 3 : TcpServerBuilder& TcpServerBuilder::read_buffer_size(size_t bytes) {
182 : 3 : read_buffer_size_ = bytes;
183 : 3 : read_buffer_size_set_ = true;
184 : 3 : return *this;
185 : : }
186 : :
187 : : // Backward compatibility implementations
188 : 3 : TcpServerBuilder& TcpServerBuilder::port_retry(bool enable, int max_retries, int retry_interval_ms) {
189 : 3 : port_retry_enabled_ = enable;
190 : 3 : port_retry_enabled_set_ = true;
191 : 3 : max_port_retries_ = static_cast<uint32_t>(max_retries);
192 : 3 : max_port_retries_set_ = true;
193 : 3 : port_retry_interval_ms_ = static_cast<uint32_t>(retry_interval_ms);
194 : 3 : port_retry_interval_set_ = true;
195 : 3 : return *this;
196 : : }
197 : :
198 : 2 : TcpServerBuilder& TcpServerBuilder::idle_timeout(std::chrono::milliseconds timeout) {
199 : 2 : idle_timeout_ = timeout;
200 : 2 : idle_timeout_set_ = true;
201 : 2 : return *this;
202 : : }
203 : :
204 : 1 : TcpServerBuilder& TcpServerBuilder::single_client() {
205 : 1 : max_clients_ = 1;
206 : 1 : client_limit_enabled_ = true;
207 : 1 : return *this;
208 : : }
209 : :
210 : 2 : TcpServerBuilder& TcpServerBuilder::multi_client(size_t max) {
211 [ + + ]: 2 : if (max == 0) {
212 : 7 : throw diagnostics::BuilderException("multi_client max must be greater than 0");
213 : : }
214 : 1 : max_clients_ = static_cast<uint32_t>(max);
215 : 1 : client_limit_enabled_ = true;
216 : 1 : return *this;
217 : : }
218 : :
219 : : // Explicit template instantiations
220 : :
221 : : } // namespace builder
222 : : } // namespace wirestead
|