rocket/listener/bounced.rs
1use std::{io, time::Duration};
2
3use crate::listener::{Listener, Endpoint};
4
5static DURATION: Duration = Duration::from_millis(250);
6
7pub struct Bounced<L> {
8 listener: L,
9}
10
11pub trait BouncedExt: Sized {
12 fn bounced(self) -> Bounced<Self> {
13 Bounced { listener: self }
14 }
15}
16
17impl<L> BouncedExt for L { }
18
19fn is_recoverable(e: &io::Error) -> bool {
20 matches!(e.kind(),
21 | io::ErrorKind::ConnectionRefused
22 | io::ErrorKind::ConnectionAborted
23 | io::ErrorKind::ConnectionReset)
24}
25
26impl<L: Listener + Sync> Bounced<L> {
27 #[inline]
28 pub async fn accept_next(&self) -> <Self as Listener>::Accept {
29 loop {
30 match self.listener.accept().await {
31 Ok(accept) => return accept,
32 Err(e) if is_recoverable(&e) => warn!("recoverable connection error: {e}"),
33 Err(e) => {
34 warn!("accept error: {e} [retrying in {}ms]", DURATION.as_millis());
35 tokio::time::sleep(DURATION).await;
36 }
37 };
38 }
39 }
40}
41
42impl<L: Listener + Sync> Listener for Bounced<L> {
43 type Accept = L::Accept;
44
45 type Connection = L::Connection;
46
47 async fn accept(&self) -> io::Result<Self::Accept> {
48 Ok(self.accept_next().await)
49 }
50
51 async fn connect(&self, accept: Self::Accept) -> io::Result<Self::Connection> {
52 self.listener.connect(accept).await
53 }
54
55 fn endpoint(&self) -> io::Result<Endpoint> {
56 self.listener.endpoint()
57 }
58}