use std::path::PathBuf;
use bytes::Bytes;
use http::HeaderMap;
use http::HeaderValue;
use http::Response;
use http::header;
use rust_embed::EmbeddedFile;
use crate::common::domain::utils::last_modified::http_date_from_unix_time;
#[derive(Debug, Clone)]
pub struct StaticAsset(pub Response<Bytes>);
impl StaticAsset {
pub fn from_rust_embed<P: AsRef<std::path::Path>>(
embedded_file: EmbeddedFile,
path: P,
) -> Result<Self, StaticAssetError> {
let mime = mime_guess::from_path(&path).first_or_octet_stream();
let mut headers = HeaderMap::new();
headers.append(
header::CONTENT_TYPE,
mime.as_ref()
.parse()
.map_err(|_e| StaticAssetError::InvalidContentTypeHeader {
mime_type: mime.to_string(),
})?,
);
if let Some(last_modified) = embedded_file.metadata.last_modified() {
let http_date = http_date_from_unix_time(last_modified);
headers.append(
header::LAST_MODIFIED,
HeaderValue::from_str(&http_date.to_string()).map_err(|_e| {
StaticAssetError::InvalidLastModifiedHeader {
http_date: http_date.to_string(),
}
})?,
);
}
let mut response = Response::builder()
.body(Bytes::from(embedded_file.data.into_owned()))
.map_err(|_e| StaticAssetError::BytesConversion {
path: path.as_ref().to_path_buf(),
})?;
*response.headers_mut() = headers;
Ok(Self(response))
}
}
#[cfg(test)]
impl StaticAsset {
pub fn data(&self) -> Vec<u8> {
self.0.body().to_vec()
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum StaticAssetError {
#[error("unable to create content-type header from {mime_type}")]
InvalidContentTypeHeader { mime_type: String },
#[error("unable to create last-modified header from {http_date}")]
InvalidLastModifiedHeader { http_date: String },
#[error("unable to convert {path} to bytes")]
BytesConversion { path: PathBuf },
}