Compare commits

..

2 Commits

Author SHA1 Message Date
409
5c09120c23 improve file streams 2025-09-06 18:00:58 +02:00
409
1c4aaa7040 improve viewer exports 2025-09-06 18:00:19 +02:00
7 changed files with 59 additions and 18 deletions

View File

@@ -116,11 +116,19 @@ pub enum FileType {
pub struct FileMimeType(String);
impl FileMimeType {
pub fn new_raw(raw: &str) -> Self {
Self(raw.to_owned())
}
pub fn from_name(name: &str) -> Option<Self> {
mime_guess::from_path(name)
.first_raw()
.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
@@ -289,27 +297,39 @@ impl From<AbsoluteFilePath> for FilePath {
pub type FileStreamInner =
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 {
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
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 {
self.0
self.file_type
}
pub fn mime_type(&self) -> Option<&FileMimeType> {
self.mime_type.as_ref()
}
pub fn stream(&self) -> &FileStreamInner {
&self.1
&self.stream
}
}
impl From<FileStream> for FileStreamInner {
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");
if let Some(headers) = builder.headers_mut() {
if self.file_type() == FileType::Directory {
if let Some(mime_type) = self.mime_type() {
headers.insert(
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.body(axum::body::Body::from_stream(inner)).unwrap()
builder
.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 {
@@ -293,7 +297,20 @@ impl FileSystem {
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)
}

View File

@@ -1,4 +1,4 @@
export const useImageViewer = defineStore('image-viewer', {
export default defineStore('image-viewer', {
state: () => ({
src: null as string | null,
}),

View File

@@ -1,4 +1,4 @@
import { useImageViewer } from './image';
import { useTextEditor } from './text';
import useImageViewer from './image';
import useTextEditor from './text';
export { useImageViewer, useTextEditor };

View File

@@ -1,7 +1,7 @@
import { uploadToWarren } from '~/lib/api/warrens';
import type { DirectoryEntry } from '~/shared/types';
export const useTextEditor = defineStore('text-editor', {
export default defineStore('text-editor', {
state: () => ({
data: null as {
warrenId: string;