view image files
This commit is contained in:
@@ -1,40 +1,65 @@
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use rustix::fs::statx;
|
||||
use tokio::{
|
||||
fs,
|
||||
io::{self, AsyncWriteExt as _},
|
||||
};
|
||||
use tokio_util::io::ReaderStream;
|
||||
|
||||
use crate::domain::warren::{
|
||||
models::file::{
|
||||
AbsoluteFilePath, CreateDirectoryError, CreateDirectoryRequest, CreateFileError,
|
||||
CreateFileRequest, DeleteDirectoryError, DeleteDirectoryRequest, DeleteFileError,
|
||||
DeleteFileRequest, File, FileMimeType, FileName, FilePath, FileType, ListFilesError,
|
||||
ListFilesRequest, RenameEntryError, RenameEntryRequest,
|
||||
use crate::{
|
||||
config::Config,
|
||||
domain::warren::{
|
||||
models::file::{
|
||||
AbsoluteFilePath, CreateDirectoryError, CreateDirectoryRequest, CreateFileError,
|
||||
CreateFileRequest, DeleteDirectoryError, DeleteDirectoryRequest, DeleteFileError,
|
||||
DeleteFileRequest, FetchFileError, FetchFileRequest, File, FileMimeType, FileName,
|
||||
FilePath, FileStream, FileType, ListFilesError, ListFilesRequest, RenameEntryError,
|
||||
RenameEntryRequest,
|
||||
},
|
||||
ports::FileSystemRepository,
|
||||
},
|
||||
ports::FileSystemRepository,
|
||||
};
|
||||
|
||||
const MAX_FILE_FETCH_BYTES: &str = "MAX_FILE_FETCH_BYTES";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileSystemConfig {
|
||||
base_directory: String,
|
||||
max_file_fetch_bytes: u64,
|
||||
}
|
||||
|
||||
impl FileSystemConfig {
|
||||
pub fn new(base_directory: String) -> Self {
|
||||
Self { base_directory }
|
||||
pub fn new(base_directory: String, max_file_fetch_bytes: u64) -> Self {
|
||||
Self {
|
||||
base_directory,
|
||||
max_file_fetch_bytes,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_env(serve_dir: String) -> anyhow::Result<Self> {
|
||||
// 268435456 bytes = 0.25GB
|
||||
let max_file_fetch_bytes: u64 = match Config::load_env(MAX_FILE_FETCH_BYTES) {
|
||||
Ok(value) => value.parse()?,
|
||||
Err(_) => 268435456,
|
||||
};
|
||||
|
||||
Ok(Self::new(serve_dir, max_file_fetch_bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileSystem {
|
||||
base_directory: FilePath,
|
||||
max_file_fetch_bytes: u64,
|
||||
}
|
||||
|
||||
impl FileSystem {
|
||||
pub fn new(config: FileSystemConfig) -> anyhow::Result<Self> {
|
||||
let file_system = Self {
|
||||
base_directory: FilePath::new(&config.base_directory)?,
|
||||
max_file_fetch_bytes: config.max_file_fetch_bytes,
|
||||
};
|
||||
|
||||
Ok(file_system)
|
||||
@@ -146,6 +171,27 @@ impl FileSystem {
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
async fn fetch_file(&self, path: &AbsoluteFilePath) -> anyhow::Result<FileStream> {
|
||||
let path = self.get_target_path(path);
|
||||
|
||||
let file = fs::OpenOptions::new()
|
||||
.create(false)
|
||||
.write(false)
|
||||
.read(true)
|
||||
.open(&path)
|
||||
.await?;
|
||||
|
||||
let file_size = file.metadata().await?.size();
|
||||
|
||||
if file_size > self.max_file_fetch_bytes {
|
||||
bail!("File size exceeds configured limit");
|
||||
}
|
||||
|
||||
let stream = FileStream::new(ReaderStream::new(file));
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
/// Actually removes a file from the underlying file system
|
||||
///
|
||||
/// * `path`: The file's absolute path (absolute not in relation to the root file system but `self.base_directory`)
|
||||
@@ -237,6 +283,15 @@ impl FileSystemRepository for FileSystem {
|
||||
Ok(file_path)
|
||||
}
|
||||
|
||||
async fn fetch_file(&self, request: FetchFileRequest) -> Result<FileStream, FetchFileError> {
|
||||
let contents = self
|
||||
.fetch_file(request.path())
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to fetch file {}: {e:?}", request.path()))?;
|
||||
|
||||
Ok(contents)
|
||||
}
|
||||
|
||||
async fn delete_file(&self, request: DeleteFileRequest) -> Result<FilePath, DeleteFileError> {
|
||||
let deleted_path = self
|
||||
.remove_file(request.path())
|
||||
|
||||
Reference in New Issue
Block a user