Skip to main content

frontend/
frontend.rs

1#![allow(clippy::std_instead_of_core)]
2
3use std::env;
4use std::io::ErrorKind;
5use std::time::{Duration, Instant};
6
7use msrt_udp::{EngineConfig, UdpClient, UdpClientEvent};
8use tokio::time::sleep;
9
10const DEFAULT_SERVER: &str = "127.0.0.1:9000";
11const SEND_INTERVAL: Duration = Duration::from_secs(1);
12const LOOP_SLEEP: Duration = Duration::from_millis(10);
13
14#[tokio::main]
15async fn main() -> msrt_udp::Result<()> {
16    let server = env::args()
17        .nth(1)
18        .unwrap_or_else(|| DEFAULT_SERVER.to_string());
19
20    let mut client = UdpClient::bind_with_config("127.0.0.1:0", &server, demo_config()).await?;
21    println!(
22        "frontend local={} remote={}",
23        client.local_addr()?,
24        client.peer_addr()?
25    );
26
27    reconnect(&mut client)?;
28    let mut sequence = 0_u64;
29    let mut next_send = Instant::now();
30
31    loop {
32        if next_send <= Instant::now() {
33            let payload = format!("hello udp {sequence}");
34            if client.send(payload.as_bytes())? {
35                println!("queued: {payload}");
36                sequence = sequence.wrapping_add(1);
37            }
38            next_send = Instant::now() + SEND_INTERVAL;
39        }
40
41        match client.tick().await? {
42            UdpClientEvent::Message(message) if message.as_bytes() != [0] => {
43                println!("message: {}", String::from_utf8_lossy(message.as_bytes()));
44            }
45            UdpClientEvent::Message(_) | UdpClientEvent::Idle => {}
46            UdpClientEvent::SendFailed(failed) => {
47                println!("send failed: {failed:?}; reconnecting");
48                client.disconnect();
49                reconnect(&mut client)?;
50                next_send = Instant::now();
51            }
52            UdpClientEvent::TransportUnavailable { kind } => {
53                println!("transport unavailable: {kind:?}; reconnecting");
54                client.disconnect();
55                reconnect(&mut client)?;
56                next_send = Instant::now() + reconnect_delay(kind);
57            }
58        }
59
60        sleep(LOOP_SLEEP).await;
61    }
62}
63
64fn reconnect_delay(kind: ErrorKind) -> Duration {
65    match kind {
66        ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset => Duration::from_millis(250),
67        _ => Duration::from_secs(1),
68    }
69}
70
71fn reconnect(client: &mut UdpClient) -> msrt_udp::Result<()> {
72    client.connect()?;
73    println!("session started");
74    Ok(())
75}
76
77fn demo_config() -> EngineConfig {
78    EngineConfig {
79        retransmit_timeout_ms: 250,
80        max_retransmit_attempts: 8,
81        ..EngineConfig::default()
82    }
83}