1use crate::{
10 connections::{Connections, Destination},
11 handshake,
12 message::Message,
13 metrics,
14 metrics::Metrics,
15 streams::mpsc,
16};
17
18#[cfg(test)]
19pub(crate) mod mocks;
20
21mod traits;
22pub use traits::*;
23
24use rand::RngCore;
25use std::sync::Arc;
26
27mod connections;
28mod heartbeat;
29
30pub use connections::{user_con, UserCon};
31
32#[derive(Debug)]
33pub(crate) enum ConnectError {
34 IO(std::io::Error),
35 Handshake(handshake::HandshakeError),
36}
37
38impl From<std::io::Error> for ConnectError {
39 fn from(other: std::io::Error) -> Self {
40 Self::IO(other)
41 }
42}
43impl From<handshake::HandshakeError> for ConnectError {
44 fn from(other: handshake::HandshakeError) -> Self {
45 Self::Handshake(other)
46 }
47}
48
49pub struct Client<M> {
52 server_destination: Destination,
53 external_port: u16,
54 key: Vec<u8>,
55 metrics: Arc<M>,
56}
57
58impl Client<metrics::Empty> {
59 pub fn new(server: Destination, external_port: u16, key: Vec<u8>) -> Self {
66 Self {
67 server_destination: server,
68 external_port,
69 key,
70 metrics: Arc::new(metrics::Empty::new()),
71 }
72 }
73}
74
75impl<M> Client<M> {
76 fn exponential_backoff(
78 attempt: u32,
79 max_time: Option<std::time::Duration>,
80 ) -> std::time::Duration {
81 let raw_time = std::time::Duration::from_secs(2u64.pow(attempt));
82 let raw_jitter = rand::rngs::ThreadRng::default().next_u64() % 1000;
83 let raw_calced = raw_time.checked_add(std::time::Duration::from_millis(raw_jitter));
84
85 match (max_time, raw_calced) {
86 (Some(max), Some(calced)) if calced > max => max,
87 (_, Some(calced)) => calced,
88 (Some(max), _) => max,
89 _ => std::time::Duration::from_millis(0),
90 }
91 }
92}
93
94impl<M> Client<M>
95where
96 M: Metrics + Send + Sync + 'static,
97{
98 pub fn new_with_metrics(
101 server: Destination,
102 external_port: u16,
103 key: Vec<u8>,
104 metrics_collector: M,
105 ) -> Self {
106 Self {
107 server_destination: server,
108 external_port,
109 key,
110 metrics: Arc::new(metrics_collector),
111 }
112 }
113
114 async fn start_con<H>(&self, handler: Arc<H>) -> Result<(), ConnectError>
122 where
123 H: Handler + Send + Sync + 'static,
124 {
125 info!("Establishing Connection...");
126
127 let target_addr = self.server_destination.get_full_address();
128 debug!("Conneting to server: {}", target_addr);
129 let mut connection = tokio::net::TcpStream::connect(target_addr).await?;
130 debug!("Connected to Server");
131
132 let handshake_conf = handshake::Config::new(self.external_port);
133
134 debug!("Starting Handshake...");
135 handshake::client::perform(&mut connection, &self.key, handshake_conf).await?;
136 debug!("Performed Handshake");
137
138 let (read_con, write_con) = connection.into_split();
139
140 info!("Established Conection");
141
142 let (queue_tx, queue_rx) = tokio::sync::mpsc::unbounded_channel();
143 let outgoing = std::sync::Arc::new(Connections::<mpsc::StreamWriter<Message>>::new());
144
145 tokio::task::spawn(heartbeat::keep_alive(
148 queue_tx.clone(),
149 std::time::Duration::from_secs(15),
150 ));
151
152 tokio::task::spawn(connections::tx::sender(
155 write_con,
156 queue_rx,
157 self.metrics.clone(),
158 ));
159
160 connections::rx::receiver(
163 read_con,
164 queue_tx.clone(),
165 outgoing,
166 handler,
167 self.metrics.clone(),
168 )
169 .await;
170
171 Ok(())
172 }
173
174 pub async fn start<H>(self, handler: Arc<H>) -> !
179 where
180 H: Handler + Send + Sync + 'static,
181 {
182 info!("Starting...");
183
184 let mut attempts = 0;
185
186 loop {
187 match self.start_con(handler.clone()).await {
188 Ok(_) => {
189 attempts = 0;
190 }
191 Err(e) => {
192 error!("Connecting: {:?}", e);
193
194 attempts += 1;
195 let wait_time = Self::exponential_backoff(
196 attempts,
197 Some(std::time::Duration::from_secs(60)),
198 );
199 info!("Waiting {:?} before trying to connect again", wait_time);
200 tokio::time::sleep(wait_time).await;
201 }
202 };
203 }
204 }
205}