use std::path::PathBuf;
#[cfg(feature = "compio")]
use compio::fs;
use http::StatusCode;
use tako_rs_core::body::TakoBody;
use tako_rs_core::responder::Responder;
use tako_rs_core::types::Request;
use tako_rs_core::types::Response;
#[cfg(not(feature = "compio"))]
use tokio::fs;
#[doc(alias = "serve_file")]
pub struct ServeFile {
path: PathBuf,
}
#[must_use]
pub struct ServeFileBuilder {
path: PathBuf,
}
impl ServeFileBuilder {
#[inline]
pub fn new<P: Into<PathBuf>>(path: P) -> Self {
Self { path: path.into() }
}
#[inline]
#[must_use]
pub fn build(self) -> ServeFile {
ServeFile { path: self.path }
}
}
impl ServeFile {
pub fn builder<P: Into<PathBuf>>(path: P) -> ServeFileBuilder {
ServeFileBuilder::new(path)
}
async fn serve_file(&self) -> Option<Response> {
match fs::read(&self.path).await {
Ok(contents) => {
let mime = mime_guess::from_path(&self.path).first_or_octet_stream();
Some(
http::Response::builder()
.status(StatusCode::OK)
.header(http::header::CONTENT_TYPE, mime.to_string())
.body(TakoBody::from(contents))
.unwrap(),
)
}
Err(_) => None,
}
}
pub async fn handle(&self, _req: Request) -> impl Responder {
if let Some(resp) = self.serve_file().await {
resp
} else {
let mut resp = http::Response::new(TakoBody::from("File not found"));
*resp.status_mut() = StatusCode::NOT_FOUND;
resp
}
}
}