use std::time::Duration;
use tokio::{
net::UdpSocket,
sync::mpsc::{Receiver, error::TryRecvError},
time::Instant,
};
use crate::{
errors::UdpOptError,
utils::{
net_utils::{IntervalResult, ServerCommand},
udp_data::{FLAG_FIN, HEADER_SIZE, UdpData, UdpHeader},
ui::print_result,
},
};
#[derive(Debug)]
pub struct AsyncUdpServer {
interval: Duration,
udp_result: Vec<IntervalResult>,
control_rx: Receiver<ServerCommand>,
}
impl AsyncUdpServer {
pub async fn new(interval: Duration, control_rx: Receiver<ServerCommand>) -> Self {
Self {
interval,
udp_result: Vec::with_capacity(100),
control_rx,
}
}
pub async fn run(&mut self, sock: &mut UdpSocket) -> Result<Vec<IntervalResult>, UdpOptError> {
println!("server start");
let mut udp_data = UdpData::new();
let mut buf = vec![0u8; 2048];
match self.control_rx.recv().await {
Some(ServerCommand::Stop) => return Err(UdpOptError::UnexpectedCommand),
Some(ServerCommand::Start) => {}
None => return Err(UdpOptError::ChannelClosed),
}
let _ = sock
.recv(&mut buf)
.await
.map_err(|e| UdpOptError::RecvFailed(e))?;
let mut calc_instat = Instant::now();
let calc_interval = Duration::from_millis(200);
let mut start = Instant::now();
loop {
match self.control_rx.try_recv() {
Ok(ServerCommand::Stop) => break,
Ok(ServerCommand::Start) => return Err(UdpOptError::UnexpectedCommand),
Err(TryRecvError::Empty) => {}
Err(TryRecvError::Disconnected) => return Err(UdpOptError::ChannelClosed),
}
let len = sock
.recv(&mut buf)
.await
.map_err(|e| UdpOptError::RecvFailed(e))?;
if len < HEADER_SIZE {
continue;
}
let header = UdpHeader::read_header(&mut buf);
udp_data.process_packet(len, &header, start.elapsed());
let time_to_calc_bitrate = calc_instat.elapsed();
if time_to_calc_bitrate >= calc_interval {
udp_data.calc_bitrate(time_to_calc_bitrate);
calc_instat = Instant::now();
}
if header.flags == FLAG_FIN {
break;
}
if start.elapsed() >= self.interval {
let res = udp_data.get_interval_result(start.elapsed());
print_result(&res);
self.udp_result.push(res);
start = Instant::now();
}
}
println!("test finished");
if self.udp_result.len() == 0 {
self.udp_result
.push(udp_data.get_interval_result(start.elapsed()));
}
Ok(self.udp_result.clone())
}
}