- differentiate between "not a directory" and a real error while reading the path - don't clone the PathBuf, instead use Arc
62 lines
1.5 KiB
Rust
62 lines
1.5 KiB
Rust
use std::{
|
|
net::{IpAddr, SocketAddr},
|
|
num::NonZeroUsize,
|
|
path::PathBuf,
|
|
sync::Arc,
|
|
thread::available_parallelism,
|
|
};
|
|
|
|
use actix_web::{App, HttpServer};
|
|
use clap::{Parser, crate_name, crate_version};
|
|
|
|
#[derive(Parser, Debug)]
|
|
#[clap(name = crate_name!(), version = crate_version!())]
|
|
struct Args {
|
|
/// Directory to expose
|
|
#[clap(default_value = ".", value_parser = parse_valid_dir)]
|
|
dir: PathBuf,
|
|
|
|
/// IP address to use
|
|
#[clap(default_value = "0.0.0.0")]
|
|
ip: IpAddr,
|
|
|
|
/// Port number to connect
|
|
#[clap(default_value = "8080")]
|
|
port: u16,
|
|
}
|
|
|
|
fn parse_valid_dir(dir: &str) -> Result<PathBuf, String> {
|
|
let path = PathBuf::from(dir);
|
|
match std::fs::metadata(&path) {
|
|
Ok(metadata) if metadata.is_dir() => Ok(path),
|
|
Ok(_) => Err(format!("{} is not a directory", path.display())),
|
|
Err(e) => Err(format!("Error accessing {}: {}", path.display(), e)),
|
|
}
|
|
}
|
|
|
|
#[actix_web::main]
|
|
async fn main() -> std::io::Result<()> {
|
|
let args = Args::parse();
|
|
|
|
let dir = Arc::new(args.dir);
|
|
let sock = SocketAddr::new(args.ip, args.port);
|
|
|
|
println!(
|
|
"Starting HTTP server on {sock} exposing dir {}",
|
|
dir.display()
|
|
);
|
|
|
|
HttpServer::new(move || {
|
|
let dir = dir.clone();
|
|
App::new().service(
|
|
actix_files::Files::new("/", dir.as_ref())
|
|
.show_files_listing()
|
|
.prefer_utf8(true),
|
|
)
|
|
})
|
|
.workers(available_parallelism().map_or(1, NonZeroUsize::get))
|
|
.bind(sock)?
|
|
.run()
|
|
.await
|
|
}
|