nntp_proxy/network/
optimizers.rs1use crate::stream::ConnectionStream;
7use std::io;
8use tokio::net::TcpStream;
9use tokio_rustls::client::TlsStream;
10use tracing::debug;
11
12pub trait NetworkOptimizer {
14 fn optimize(&self) -> Result<(), io::Error>;
16
17 fn description(&self) -> &'static str;
19}
20
21pub struct TcpOptimizer<'a> {
23 stream: &'a TcpStream,
24 recv_buffer_size: usize,
25 send_buffer_size: usize,
26}
27
28impl<'a> TcpOptimizer<'a> {
29 pub fn new(stream: &'a TcpStream) -> Self {
31 Self {
32 stream,
33 recv_buffer_size: crate::constants::socket::HIGH_THROUGHPUT_RECV_BUFFER,
34 send_buffer_size: crate::constants::socket::HIGH_THROUGHPUT_SEND_BUFFER,
35 }
36 }
37
38 pub fn with_buffer_sizes(stream: &'a TcpStream, recv_size: usize, send_size: usize) -> Self {
40 Self {
41 stream,
42 recv_buffer_size: recv_size,
43 send_buffer_size: send_size,
44 }
45 }
46}
47
48impl<'a> NetworkOptimizer for TcpOptimizer<'a> {
49 fn optimize(&self) -> Result<(), io::Error> {
50 use socket2::SockRef;
51
52 let sock_ref = SockRef::from(self.stream);
53
54 sock_ref.set_recv_buffer_size(self.recv_buffer_size)?;
56 sock_ref.set_send_buffer_size(self.send_buffer_size)?;
57
58 debug!(
59 "Applied TCP optimizations: recv_buffer={}, send_buffer={}",
60 self.recv_buffer_size, self.send_buffer_size
61 );
62
63 Ok(())
64 }
65
66 fn description(&self) -> &'static str {
67 "TCP high-throughput optimization"
68 }
69}
70
71pub struct TlsOptimizer<'a> {
73 stream: &'a TlsStream<TcpStream>,
74 recv_buffer_size: usize,
75 send_buffer_size: usize,
76}
77
78impl<'a> TlsOptimizer<'a> {
79 pub fn new(stream: &'a TlsStream<TcpStream>) -> Self {
81 Self {
82 stream,
83 recv_buffer_size: crate::constants::socket::HIGH_THROUGHPUT_RECV_BUFFER,
84 send_buffer_size: crate::constants::socket::HIGH_THROUGHPUT_SEND_BUFFER,
85 }
86 }
87
88 pub fn with_buffer_sizes(
90 stream: &'a TlsStream<TcpStream>,
91 recv_size: usize,
92 send_size: usize,
93 ) -> Self {
94 Self {
95 stream,
96 recv_buffer_size: recv_size,
97 send_buffer_size: send_size,
98 }
99 }
100}
101
102impl<'a> NetworkOptimizer for TlsOptimizer<'a> {
103 fn optimize(&self) -> Result<(), io::Error> {
104 use socket2::SockRef;
105
106 let tcp_stream = self.stream.get_ref().0;
108 let sock_ref = SockRef::from(tcp_stream);
109
110 sock_ref.set_recv_buffer_size(self.recv_buffer_size)?;
112 sock_ref.set_send_buffer_size(self.send_buffer_size)?;
113
114 debug!(
115 "Applied TLS optimizations to underlying TCP stream: recv_buffer={}, send_buffer={}",
116 self.recv_buffer_size, self.send_buffer_size
117 );
118
119 Ok(())
120 }
121
122 fn description(&self) -> &'static str {
123 "TLS optimization via underlying TCP stream"
124 }
125}
126
127pub struct ConnectionOptimizer<'a> {
129 stream: &'a ConnectionStream,
130 recv_buffer_size: Option<usize>,
131 send_buffer_size: Option<usize>,
132}
133
134impl<'a> ConnectionOptimizer<'a> {
135 pub fn new(stream: &'a ConnectionStream) -> Self {
137 Self {
138 stream,
139 recv_buffer_size: None,
140 send_buffer_size: None,
141 }
142 }
143
144 pub fn with_buffer_sizes(
146 stream: &'a ConnectionStream,
147 recv_size: usize,
148 send_size: usize,
149 ) -> Self {
150 Self {
151 stream,
152 recv_buffer_size: Some(recv_size),
153 send_buffer_size: Some(send_size),
154 }
155 }
156}
157
158impl<'a> NetworkOptimizer for ConnectionOptimizer<'a> {
159 fn optimize(&self) -> Result<(), io::Error> {
160 match (self.recv_buffer_size, self.send_buffer_size) {
161 (Some(recv), Some(send)) => {
162 match self.stream {
164 ConnectionStream::Plain(tcp) => {
165 let optimizer = TcpOptimizer::with_buffer_sizes(tcp, recv, send);
166 debug!("Using {} with custom buffers", optimizer.description());
167 optimizer.optimize()
168 }
169 ConnectionStream::Tls(tls) => {
170 let optimizer = TlsOptimizer::with_buffer_sizes(tls.as_ref(), recv, send);
171 debug!("Using {} with custom buffers", optimizer.description());
172 optimizer.optimize()
173 }
174 }
175 }
176 _ => {
177 match self.stream {
179 ConnectionStream::Plain(tcp) => {
180 let optimizer = TcpOptimizer::new(tcp);
181 debug!("Using {}", optimizer.description());
182 optimizer.optimize()
183 }
184 ConnectionStream::Tls(tls) => {
185 let optimizer = TlsOptimizer::new(tls.as_ref());
186 debug!("Using {}", optimizer.description());
187 optimizer.optimize()
188 }
189 }
190 }
191 }
192 }
193
194 fn description(&self) -> &'static str {
195 match self.stream {
196 ConnectionStream::Plain(_) => "Connection-level TCP optimization",
197 ConnectionStream::Tls(_) => "Connection-level TLS optimization",
198 }
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use tokio::net::TcpListener;
206
207 #[tokio::test]
208 async fn test_tcp_optimizer() {
209 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
210 let addr = listener.local_addr().unwrap();
211
212 let stream = tokio::net::TcpStream::connect(addr).await.unwrap();
213 let optimizer = TcpOptimizer::new(&stream);
214
215 assert_eq!(optimizer.description(), "TCP high-throughput optimization");
216
217 let _ = optimizer.optimize();
219 }
220
221 #[tokio::test]
222 async fn test_connection_optimizer_tcp() {
223 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
224 let addr = listener.local_addr().unwrap();
225
226 let tcp_stream = tokio::net::TcpStream::connect(addr).await.unwrap();
227 let connection_stream = ConnectionStream::Plain(tcp_stream);
228 let optimizer = ConnectionOptimizer::new(&connection_stream);
229
230 assert_eq!(optimizer.description(), "Connection-level TCP optimization");
231
232 let _ = optimizer.optimize();
234 }
235
236 #[tokio::test]
237 async fn test_connection_optimizer_trait_usage() {
238 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
239 let addr = listener.local_addr().unwrap();
240
241 let tcp_stream = tokio::net::TcpStream::connect(addr).await.unwrap();
242 let connection_stream = ConnectionStream::Plain(tcp_stream);
243
244 let optimizer: Box<dyn NetworkOptimizer> =
246 Box::new(ConnectionOptimizer::new(&connection_stream));
247
248 assert_eq!(optimizer.description(), "Connection-level TCP optimization");
249 let _ = optimizer.optimize();
250 }
251
252 #[tokio::test]
253 async fn test_connection_optimizer_with_custom_buffers() {
254 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
255 let addr = listener.local_addr().unwrap();
256
257 let tcp_stream = tokio::net::TcpStream::connect(addr).await.unwrap();
258 let connection_stream = ConnectionStream::Plain(tcp_stream);
259 let optimizer = ConnectionOptimizer::with_buffer_sizes(&connection_stream, 4096, 8192);
260
261 assert_eq!(optimizer.description(), "Connection-level TCP optimization");
262 let _ = optimizer.optimize();
263 }
264
265 #[tokio::test]
266 async fn test_optimizer_creation() {
267 let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
269 let addr = listener.local_addr().unwrap();
270
271 let tokio_stream = tokio::net::TcpStream::connect(addr).await.unwrap();
272
273 let optimizer = TcpOptimizer::new(&tokio_stream);
274 assert_eq!(
275 optimizer.recv_buffer_size,
276 crate::constants::socket::HIGH_THROUGHPUT_RECV_BUFFER
277 );
278 assert_eq!(
279 optimizer.send_buffer_size,
280 crate::constants::socket::HIGH_THROUGHPUT_SEND_BUFFER
281 );
282 }
283
284 #[tokio::test]
285 async fn test_custom_buffer_sizes() {
286 let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
287 let addr = listener.local_addr().unwrap();
288
289 let tokio_stream = tokio::net::TcpStream::connect(addr).await.unwrap();
290
291 let optimizer = TcpOptimizer::with_buffer_sizes(&tokio_stream, 1024, 2048);
292 assert_eq!(optimizer.recv_buffer_size, 1024);
293 assert_eq!(optimizer.send_buffer_size, 2048);
294 }
295}