CS3700-project3/hptp-recv/src/main.rs

68 lines
1.6 KiB
Rust

#![feature(backtrace)]
extern crate hptp;
extern crate tokio;
#[macro_use]
extern crate thiserror;
use hptp::log::Logger;
use hptp::msg::Msg;
use hptp::peer::Peer;
use tokio::io::AsyncWrite;
#[derive(Error, Debug)]
enum Error {
#[error("io error: {source}")]
Io {
#[from]
source: tokio::io::Error,
backtrace: std::backtrace::Backtrace,
},
#[error("no UDP port available for listening")]
NoPortAvail,
}
fn entry() -> Result<(), Error> {
let mut rt = tokio::runtime::Runtime::new().unwrap();
let mut log = Logger::new();
rt.block_on(start(&mut log))
}
fn main() {
if let Err(e) = entry() {
use std::error::Error;
println!("Error: {}", e);
for bt in e.backtrace() {
println!("{}", bt);
}
}
}
async fn start(log: &mut Logger) -> Result<(), Error> {
let sock = hptp::udp_retrying_bind(16, hptp::random_port)
.await
.map_err(|_| Error::NoPortAvail)?;
log.bound(sock.local_addr()?.port()).await;
let mut out = tokio::io::stdout();
let mut peer = Peer::new(sock);
download(log, &mut peer, &mut out).await
}
async fn download<OUT>(log: &mut Logger, peer: &mut Peer, out: &mut OUT) -> Result<(), Error>
where
OUT: AsyncWrite + Unpin,
{
use tokio::io::AsyncWriteExt;
let mut pos = 0;
loop {
match peer.recv().await? {
Msg::Data(data) => {
let len = data.len();
out.write_all(&data).await?;
out.flush().await?;
log.recv_data_accepted(pos, len, hptp::log::InOrder).await;
pos += len;
}
}
}
}