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())
|
||||
|
||||
@@ -52,6 +52,13 @@ impl WarrenMetrics for MetricsDebugLogger {
|
||||
tracing::debug!("[Metrics] Fetch warrens failed");
|
||||
}
|
||||
|
||||
async fn record_warren_fetch_file_success(&self) {
|
||||
tracing::debug!("[Metrics] Fetch warren file succeeded");
|
||||
}
|
||||
async fn record_warren_fetch_file_failure(&self) {
|
||||
tracing::debug!("[Metrics] Fetch warren file failed");
|
||||
}
|
||||
|
||||
async fn record_list_warren_files_success(&self) {
|
||||
tracing::debug!("[Metrics] Warren list files succeeded");
|
||||
}
|
||||
@@ -134,6 +141,13 @@ impl FileSystemMetrics for MetricsDebugLogger {
|
||||
tracing::debug!("[Metrics] File creation failed");
|
||||
}
|
||||
|
||||
async fn record_file_fetch_success(&self) {
|
||||
tracing::debug!("[Metrics] File fetch succeeded");
|
||||
}
|
||||
async fn record_file_fetch_failure(&self) {
|
||||
tracing::debug!("[Metrics] File fetch failed");
|
||||
}
|
||||
|
||||
async fn record_file_deletion_success(&self) {
|
||||
tracing::debug!("[Metrics] File deletion succeeded");
|
||||
}
|
||||
@@ -255,6 +269,13 @@ impl AuthMetrics for MetricsDebugLogger {
|
||||
tracing::debug!("[Metrics] User warren deletion failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_fetch_file_success(&self) {
|
||||
tracing::debug!("[Metrics] Warren file fetch succeeded");
|
||||
}
|
||||
async fn record_auth_warren_fetch_file_failure(&self) {
|
||||
tracing::debug!("[Metrics] Warren file fetch failed");
|
||||
}
|
||||
|
||||
async fn record_auth_fetch_user_warren_list_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren list succeeded");
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use uuid::Uuid;
|
||||
use crate::domain::warren::{
|
||||
models::{
|
||||
auth_session::requests::FetchAuthSessionResponse,
|
||||
file::{File, FilePath},
|
||||
file::{AbsoluteFilePath, File, FilePath},
|
||||
user::{ListAllUsersAndWarrensResponse, LoginUserResponse, User},
|
||||
user_warren::UserWarren,
|
||||
warren::{
|
||||
@@ -46,6 +46,14 @@ impl WarrenNotifier for NotifierDebugLogger {
|
||||
tracing::debug!("[Notifier] Fetched warren {}", warren.name());
|
||||
}
|
||||
|
||||
async fn warren_file_fetched(&self, warren: &Warren, path: &AbsoluteFilePath) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Fetched file {} in warren {}",
|
||||
path,
|
||||
warren.name(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn warren_files_listed(&self, response: &ListWarrenFilesResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Listed {} file(s) in warren {}",
|
||||
@@ -121,6 +129,10 @@ impl FileSystemNotifier for NotifierDebugLogger {
|
||||
tracing::debug!("[Notifier] Created file {}", path);
|
||||
}
|
||||
|
||||
async fn file_fetched(&self, path: &AbsoluteFilePath) {
|
||||
tracing::debug!("[Notifier] Fetched file {path}");
|
||||
}
|
||||
|
||||
async fn file_deleted(&self, path: &FilePath) {
|
||||
tracing::debug!("[Notifier] Deleted file {}", path);
|
||||
}
|
||||
@@ -269,6 +281,18 @@ impl AuthNotifier for NotifierDebugLogger {
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_file_fetched(
|
||||
&self,
|
||||
user: &User,
|
||||
warren_id: &Uuid,
|
||||
path: &AbsoluteFilePath,
|
||||
) {
|
||||
tracing::debug!(
|
||||
"[Notifier] User {} fetched file {path} in warren {warren_id}",
|
||||
user.id(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_files_listed(&self, user: &User, response: &ListWarrenFilesResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Listed {} file(s) in warren {} for authenticated user {}",
|
||||
|
||||
Reference in New Issue
Block a user