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_client_builder.hpp"
18 : :
19 : : #include <boost/asio/io_context.hpp>
20 : :
21 : : #include "wirestead/base/constants.hpp"
22 : : #include "wirestead/builder/auto_initializer.hpp"
23 : : #include "wirestead/config/validation.hpp"
24 : : #include "wirestead/diagnostics/exceptions.hpp"
25 : : #include "wirestead/util/input_validator.hpp"
26 : :
27 : : namespace wirestead {
28 : : namespace builder {
29 : :
30 : 108 : TcpClientBuilder::TcpClientBuilder(const std::string& host, uint16_t port)
31 : 108 : : host_(host),
32 : 108 : port_(port),
33 : 108 : auto_start_(false),
34 : 108 : independent_context_(false),
35 : 108 : retry_interval_(base::constants::DEFAULT_RETRY_INTERVAL_MS),
36 : 108 : max_retries_(base::constants::DEFAULT_MAX_RETRIES),
37 : 108 : connection_timeout_(base::constants::DEFAULT_CONNECTION_TIMEOUT_MS),
38 : 216 : idle_timeout_(0),
39 : 108 : idle_timeout_action_(IdleTimeoutAction::Reconnect),
40 : 108 : tcp_no_delay_(true),
41 : 108 : keep_alive_(false),
42 : 108 : send_buffer_size_(0),
43 : 108 : receive_buffer_size_(0),
44 : 324 : read_buffer_size_(base::constants::DEFAULT_READ_BUFFER_SIZE) {
45 [ + + + - : 120 : if (port == 0) throw diagnostics::BuilderException("Invalid port number: 0");
+ - + - +
- ]
46 [ + + + - : 118 : if (host.empty()) throw diagnostics::BuilderException("Host cannot be empty");
+ - + - +
- ]
47 : :
48 : : // Ensure background IO service is running
49 : 104 : AutoInitializer::ensure_io_context_running();
50 : 116 : }
51 : :
52 : 103 : std::unique_ptr<wrapper::TcpClient> TcpClientBuilder::build() {
53 : 103 : std::unique_ptr<wrapper::TcpClient> client;
54 [ + + ]: 103 : if (independent_context_) {
55 : 3 : client = std::make_unique<wrapper::TcpClient>(host_, port_, std::make_shared<boost::asio::io_context>());
56 : 3 : client->manage_external_context(true);
57 : : } else {
58 : 100 : client = std::make_unique<wrapper::TcpClient>(host_, port_);
59 : : }
60 : :
61 [ + + + - : 103 : if (this->on_data_) client->on_data(this->on_data_);
+ - ]
62 [ + + + - : 103 : if (this->on_data_batch_) client->on_data_batch(this->on_data_batch_);
+ - ]
63 [ + + + - : 103 : if (this->on_connect_) client->on_connect(this->on_connect_);
+ - ]
64 [ + + + - : 103 : if (this->on_disconnect_) client->on_disconnect(this->on_disconnect_);
+ - ]
65 [ + + + - : 103 : if (this->on_error_) client->on_error(this->on_error_);
+ - ]
66 [ + + + - : 103 : if (this->on_backpressure_) client->on_backpressure(this->on_backpressure_);
+ - ]
67 : :
68 [ + + + - ]: 103 : if (retry_interval_set_) client->retry_interval(retry_interval_);
69 [ + + + - ]: 103 : if (max_retries_set_) client->max_retries(max_retries_);
70 [ - + - - ]: 103 : if (tls_enabled_) client->tls(tls_ca_file_);
71 [ + + + - ]: 103 : if (connection_timeout_set_) client->connection_timeout(connection_timeout_);
72 [ + + + - ]: 103 : if (idle_timeout_set_) client->idle_timeout(idle_timeout_);
73 [ + + + - ]: 103 : if (idle_timeout_action_set_) client->idle_timeout_action(idle_timeout_action_);
74 [ + + + - ]: 103 : if (tcp_no_delay_set_) client->tcp_no_delay(tcp_no_delay_);
75 [ + + + - ]: 103 : if (keep_alive_set_) client->keep_alive(keep_alive_);
76 [ + + + - ]: 103 : if (send_buffer_size_set_) client->send_buffer_size(send_buffer_size_);
77 [ + + + - ]: 103 : if (receive_buffer_size_set_) client->receive_buffer_size(receive_buffer_size_);
78 [ - + - - ]: 103 : if (read_buffer_size_set_) client->read_buffer_size(read_buffer_size_);
79 : :
80 [ + + + - ]: 103 : if (this->bp_strategy_set_) client->backpressure_strategy(this->bp_strategy_);
81 : 103 : client->backpressure_threshold(this->get_effective_backpressure_threshold());
82 : :
83 [ + + ]: 103 : if (this->framer_factory_) {
84 : 1 : client->framer(this->framer_factory_());
85 : : }
86 [ + + ]: 103 : if (this->on_message_) {
87 : 1 : client->on_message(this->on_message_);
88 : : }
89 [ + + ]: 103 : if (this->on_message_batch_) {
90 : 1 : client->on_message_batch(this->on_message_batch_);
91 : : }
92 : :
93 [ + + ]: 103 : if (auto_start_) {
94 : 8 : client->auto_start(true);
95 : : }
96 : :
97 : 103 : return client;
98 : 0 : }
99 : :
100 : 11 : TcpClientBuilder& TcpClientBuilder::auto_start(bool auto_start) {
101 : 11 : auto_start_ = auto_start;
102 : 11 : return *this;
103 : : }
104 : :
105 : 5 : TcpClientBuilder& TcpClientBuilder::retry_interval(std::chrono::milliseconds interval) {
106 : 5 : config::detail::duration(interval, base::constants::MIN_RETRY_INTERVAL_MS, base::constants::MAX_RETRY_INTERVAL_MS,
107 : : false, "invalid retry_interval");
108 : 4 : retry_interval_ = interval;
109 : 4 : retry_interval_set_ = true;
110 : 4 : return *this;
111 : : }
112 : :
113 : 9 : TcpClientBuilder& TcpClientBuilder::max_retries(int max_retries) {
114 : 9 : config::detail::range(max_retries, -1, base::constants::MAX_RETRIES_LIMIT, "invalid retry limit");
115 : 8 : max_retries_ = max_retries;
116 : 8 : max_retries_set_ = true;
117 : 8 : return *this;
118 : : }
119 : :
120 : 0 : TcpClientBuilder& TcpClientBuilder::tls(const std::string& ca_file) {
121 : 0 : tls_enabled_ = true;
122 : 0 : tls_ca_file_ = ca_file;
123 : 0 : return *this;
124 : : }
125 : :
126 : 1 : TcpClientBuilder& TcpClientBuilder::connection_timeout(std::chrono::milliseconds timeout) {
127 : 1 : config::detail::duration(timeout, base::constants::MIN_CONNECTION_TIMEOUT_MS,
128 : : base::constants::MAX_CONNECTION_TIMEOUT_MS, false, "invalid connection_timeout");
129 : 1 : connection_timeout_ = timeout;
130 : 1 : connection_timeout_set_ = true;
131 : 1 : return *this;
132 : : }
133 : :
134 : 4 : TcpClientBuilder& TcpClientBuilder::idle_timeout(std::chrono::milliseconds timeout) {
135 : 4 : config::detail::duration(timeout, base::constants::MIN_IDLE_TIMEOUT_MS, base::constants::MAX_IDLE_TIMEOUT_MS, true,
136 : : "invalid idle_timeout");
137 : 4 : idle_timeout_ = timeout;
138 : 4 : idle_timeout_set_ = true;
139 : 4 : return *this;
140 : : }
141 : :
142 : 3 : TcpClientBuilder& TcpClientBuilder::idle_timeout_action(IdleTimeoutAction action) {
143 [ - + - - ]: 3 : config::detail::require(action == IdleTimeoutAction::Close || action == IdleTimeoutAction::Reconnect,
144 : : "invalid idle timeout action");
145 : 3 : idle_timeout_action_ = action;
146 : 3 : idle_timeout_action_set_ = true;
147 : 3 : return *this;
148 : : }
149 : :
150 : 3 : TcpClientBuilder& TcpClientBuilder::independent_context(bool use_independent) {
151 : 3 : independent_context_ = use_independent;
152 : 3 : return *this;
153 : : }
154 : :
155 : 1 : TcpClientBuilder& TcpClientBuilder::tcp_no_delay(bool enable) {
156 : 1 : tcp_no_delay_ = enable;
157 : 1 : tcp_no_delay_set_ = true;
158 : 1 : return *this;
159 : : }
160 : :
161 : 1 : TcpClientBuilder& TcpClientBuilder::keep_alive(bool enable) {
162 : 1 : keep_alive_ = enable;
163 : 1 : keep_alive_set_ = true;
164 : 1 : return *this;
165 : : }
166 : :
167 : 1 : TcpClientBuilder& TcpClientBuilder::send_buffer_size(size_t bytes) {
168 [ + - ]: 1 : if (bytes != 0)
169 : 1 : config::detail::range(bytes, base::constants::MIN_SOCKET_BUFFER_SIZE, base::constants::MAX_SOCKET_BUFFER_SIZE,
170 : : "invalid send_buffer_size");
171 : 1 : send_buffer_size_ = bytes;
172 : 1 : send_buffer_size_set_ = true;
173 : 1 : return *this;
174 : : }
175 : :
176 : 1 : TcpClientBuilder& TcpClientBuilder::receive_buffer_size(size_t bytes) {
177 [ + - ]: 1 : if (bytes != 0)
178 : 1 : config::detail::range(bytes, base::constants::MIN_SOCKET_BUFFER_SIZE, base::constants::MAX_SOCKET_BUFFER_SIZE,
179 : : "invalid receive_buffer_size");
180 : 1 : receive_buffer_size_ = bytes;
181 : 1 : receive_buffer_size_set_ = true;
182 : 1 : return *this;
183 : : }
184 : :
185 : 1 : TcpClientBuilder& TcpClientBuilder::read_buffer_size(size_t bytes) {
186 : 1 : config::detail::range(bytes, base::constants::MIN_READ_BUFFER_SIZE, base::constants::MAX_READ_BUFFER_SIZE,
187 : : "invalid read_buffer_size");
188 : 0 : read_buffer_size_ = bytes;
189 : 0 : read_buffer_size_set_ = true;
190 : 0 : return *this;
191 : : }
192 : :
193 : : // Explicit template instantiations
194 : :
195 : : } // namespace builder
196 : : } // namespace wirestead
|