mod common;
use anyhow::{Context, Result};
use common::Config;
use hyper::server::conn;
use hyper_util::rt::TokioIo;
use serdir::ServedDirBuilder;
use std::net::{Ipv4Addr, SocketAddr};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> Result<()> {
run().await
}
async fn run() -> Result<()> {
let config = Config::from_env();
let mut builder = ServedDirBuilder::new(config.directory.as_str())
.context("failed to create ServedDir builder")?
.append_index_html(true)
.compression(config.compression_strategy())
.strip_prefix(config.strip_prefix.unwrap_or_default());
if let Some(path) = config.not_found_path {
builder = builder
.not_found_path(path)
.context("failed to set --not-found-path")?;
}
let served_dir = builder.build();
let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 1337));
let listener = TcpListener::bind(addr)
.await
.with_context(|| format!("failed to bind {addr}"))?;
println!(
"Serving {} on http://{}",
served_dir.dir().display(),
listener
.local_addr()
.context("failed to get listener address")?
);
let service = served_dir.into_hyper_service();
loop {
let (tcp, _) = listener.accept().await.context("accept failed")?;
let service = service.clone();
tokio::spawn(async move {
tcp.set_nodelay(true).context("failed to set TCP_NODELAY")?;
let io = TokioIo::new(tcp);
conn::http1::Builder::new()
.serve_connection(io, service)
.await
.context("connection error")?;
Ok::<(), anyhow::Error>(())
});
}
}