.await?.await?.await?

pull/1/head
dvkt 4 years ago
parent 09d691c568
commit 12bc20bce8

@ -11,16 +11,51 @@ type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>
const MAX_PEEK_SIZE: usize = 1024; const MAX_PEEK_SIZE: usize = 1024;
#[derive(Default)]
pub struct Request {
selector: String, // client info
root: String, // server info
host: String,
port: String,
}
impl Request {
pub fn new() -> Request {
Default::default()
}
pub async fn path(&self) -> Result<PathBuf> {
let mut path = fs::canonicalize(&self.root).await?;
path.push(self.selector.replace("..", ".").trim_start_matches('/'));
Ok(path)
}
pub async fn path_string(&self) -> Result<String> {
let path = self.path().await?;
Ok(path.to_string_lossy().to_string())
}
}
pub fn start(addr: impl ToSocketAddrs, root: &str) -> Result<()> { pub fn start(addr: impl ToSocketAddrs, root: &str) -> Result<()> {
task::block_on(async { task::block_on(async {
let listener = TcpListener::bind(addr).await?; let listener = TcpListener::bind(addr).await?;
let mut incoming = listener.incoming(); let mut incoming = listener.incoming();
let local_addr = listener.local_addr()?;
let host = local_addr.ip();
let port = local_addr.port();
let root = fs::canonicalize(&root).await?.to_string_lossy().to_string();
while let Some(stream) = incoming.next().await { while let Some(stream) = incoming.next().await {
let stream = stream?; let stream = stream?;
println!("-> Connection from: {}", stream.peer_addr()?); println!("-> Connection from: {}", stream.peer_addr()?);
let root = root.to_string(); let req = Request {
root: root.to_string(),
host: host.to_string(),
port: port.to_string(),
..Default::default()
};
task::spawn(async { task::spawn(async {
if let Err(e) = client_loop(stream, root).await { if let Err(e) = client_loop(stream, req).await {
eprintln!("-> {}", e); eprintln!("-> {}", e);
} }
}); });
@ -29,52 +64,58 @@ pub fn start(addr: impl ToSocketAddrs, root: &str) -> Result<()> {
}) })
} }
async fn client_loop(mut stream: TcpStream, root: String) -> Result<()> { async fn client_loop(mut stream: TcpStream, mut req: Request) -> Result<()> {
let reader = BufReader::new(&stream); let reader = BufReader::new(&stream);
let mut lines = reader.lines(); let mut lines = reader.lines();
if let Some(Ok(line)) = lines.next().await { if let Some(Ok(line)) = lines.next().await {
println!("-> {} sent: {:?}", stream.peer_addr()?, line); println!("-> {} sent: {:?}", stream.peer_addr()?, line);
respond(&mut stream, &line, &root).await?; req.selector = line;
respond(&mut stream, req).await?;
} }
Ok(()) Ok(())
} }
async fn respond(stream: &mut TcpStream, selector: &str, root: &str) -> Result<()> { async fn respond(stream: &mut TcpStream, req: Request) -> Result<()> {
let mut path = fs::canonicalize(root).await?; let mut path = fs::canonicalize(&req.root).await?;
path.push(selector.replace("..", ".").trim_start_matches('/')); path.push(req.selector.replace("..", ".").trim_start_matches('/'));
println!("path {:?}", path); println!("path {:?}", path);
let md = fs::metadata(path.clone()).await?; let md = fs::metadata(path.clone()).await?;
if md.is_file() { if md.is_file() {
return send_text(stream, path).await; return send_text(stream, req).await;
} else if md.is_dir() { } else if md.is_dir() {
return send_dir(stream, path).await; return send_dir(stream, req).await;
} else { } else {
Ok(()) Ok(())
} }
} }
async fn send_dir(stream: &mut TcpStream, path: PathBuf) -> Result<()> { async fn send_dir(stream: &mut TcpStream, req: Request) -> Result<()> {
let mut response = String::new(); let mut response = String::new();
let mut dir = fs::read_dir(path.clone()).await?; let mut dir = fs::read_dir(req.path().await?).await?;
let mut path = req.path_string().await?.replace(&req.root, "");
if !path.ends_with('/') {
path.push('/');
}
while let Some(Ok(entry)) = dir.next().await { while let Some(Ok(entry)) = dir.next().await {
let file_type = file_type(&entry).await; let file_type = file_type(&entry).await;
let f = entry.file_name(); let f = entry.file_name();
let file_name = f.to_string_lossy(); let file_name = f.to_string_lossy();
response.push_str(&format!( response.push_str(&format!(
"{}{}\t{}\tlocalhost\t7070\r\n", "{}{}\t{}{}\tlocalhost\t7070\r\n",
file_type, file_name, file_name, file_type, file_name, path, file_name,
)); ));
} }
stream.write_all(response.as_bytes()).await?; stream.write_all(response.as_bytes()).await?;
stream.write_all(b".\r\n").await?; // end gopher response stream.write_all(b"\r\n.\r\n").await?; // end gopher response
Ok(()) Ok(())
} }
async fn send_text(stream: &mut TcpStream, path: PathBuf) -> Result<()> { async fn send_text(stream: &mut TcpStream, req: Request) -> Result<()> {
let md = fs::metadata(path.clone()).await?; let path = req.path().await?;
let mut f = fs::File::open(path).await?; let md = fs::metadata(&path).await?;
let mut f = fs::File::open(&path).await?;
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let mut bytes = md.len(); let mut bytes = md.len();
while bytes > 0 { while bytes > 0 {
@ -82,7 +123,7 @@ async fn send_text(stream: &mut TcpStream, path: PathBuf) -> Result<()> {
bytes -= n as u64; bytes -= n as u64;
stream.write_all(&buf).await?; stream.write_all(&buf).await?;
} }
stream.write_all(b".\r\n").await?; // end gopher response stream.write_all(b"\r\n.\r\n").await?; // end gopher response
Ok(()) Ok(())
} }

Loading…
Cancel
Save