#![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(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; } } } }