improve file streams

This commit is contained in:
2025-09-06 18:00:58 +02:00
parent 1c4aaa7040
commit 5c09120c23
4 changed files with 55 additions and 14 deletions

View File

@@ -116,11 +116,19 @@ pub enum FileType {
pub struct FileMimeType(String); pub struct FileMimeType(String);
impl FileMimeType { impl FileMimeType {
pub fn new_raw(raw: &str) -> Self {
Self(raw.to_owned())
}
pub fn from_name(name: &str) -> Option<Self> { pub fn from_name(name: &str) -> Option<Self> {
mime_guess::from_path(name) mime_guess::from_path(name)
.first_raw() .first_raw()
.map(|s| Self(s.to_owned())) .map(|s| Self(s.to_owned()))
} }
pub fn as_str(&self) -> &str {
self.0.as_str()
}
} }
/// A valid file path that might start with a slash /// A valid file path that might start with a slash
@@ -289,27 +297,39 @@ impl From<AbsoluteFilePath> for FilePath {
pub type FileStreamInner = pub type FileStreamInner =
Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static>; Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static>;
pub struct FileStream(FileType, FileStreamInner); pub struct FileStream {
file_type: FileType,
mime_type: Option<FileMimeType>,
stream: FileStreamInner,
}
impl FileStream { impl FileStream {
pub fn new<S>(file_type: FileType, stream: S) -> Self pub fn new<S>(file_type: FileType, mime_type: Option<FileMimeType>, stream: S) -> Self
where where
S: Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static, S: Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static,
{ {
Self(file_type, Box::new(stream)) Self {
file_type,
mime_type,
stream: Box::new(stream),
}
} }
pub fn file_type(&self) -> FileType { pub fn file_type(&self) -> FileType {
self.0 self.file_type
}
pub fn mime_type(&self) -> Option<&FileMimeType> {
self.mime_type.as_ref()
} }
pub fn stream(&self) -> &FileStreamInner { pub fn stream(&self) -> &FileStreamInner {
&self.1 &self.stream
} }
} }
impl From<FileStream> for FileStreamInner { impl From<FileStream> for FileStreamInner {
fn from(value: FileStream) -> Self { fn from(value: FileStream) -> Self {
value.1 value.stream
} }
} }

View File

@@ -76,18 +76,22 @@ impl IntoResponse for FileStream {
let mut builder = Response::builder().header(http::header::TRANSFER_ENCODING, "chunked"); let mut builder = Response::builder().header(http::header::TRANSFER_ENCODING, "chunked");
if let Some(headers) = builder.headers_mut() { if let Some(headers) = builder.headers_mut() {
if self.file_type() == FileType::Directory { if let Some(mime_type) = self.mime_type() {
headers.insert( headers.insert(
http::header::CONTENT_TYPE, http::header::CONTENT_TYPE,
HeaderValue::from_str("application/zip").unwrap(), HeaderValue::from_str(mime_type.as_str()).unwrap(),
); );
} }
headers.remove(http::header::CONTENT_LENGTH); headers.insert(
http::header::TRANSFER_ENCODING,
HeaderValue::from_str("chunked").unwrap(),
);
} }
let inner: FileStreamInner = self.into(); builder
builder.body(axum::body::Body::from_stream(inner)).unwrap() .body(axum::body::Body::from_stream(FileStreamInner::from(self)))
.unwrap()
} }
} }

View File

@@ -265,7 +265,11 @@ impl FileSystem {
} }
}); });
FileStream::new(FileType::Directory, ReceiverStream::new(rx)) FileStream::new(
FileType::Directory,
Some(FileMimeType::new_raw("application/zip")),
ReceiverStream::new(rx),
)
} }
match path_request { match path_request {
@@ -293,7 +297,20 @@ impl FileSystem {
bail!("File size exceeds configured limit"); bail!("File size exceeds configured limit");
} }
let stream = FileStream::new(FileType::File, ReaderStream::new(file)); let mime_type = {
let file_name = {
let path = file_path.as_str();
if let Some(last_slash_index) = path.rfind("/") {
&path[last_slash_index + 1..]
} else {
path
}
};
FileMimeType::from_name(file_name)
};
let stream = FileStream::new(FileType::File, mime_type, ReaderStream::new(file));
Ok(stream) Ok(stream)
} }