style: fix clippy collapsible_if + cargo fmt

This commit is contained in:
Dionisio
2026-02-15 18:04:32 +01:00
parent 1ed20f425f
commit 0be7ef8c0b
11 changed files with 138 additions and 94 deletions
+1 -2
View File
@@ -150,8 +150,7 @@ impl CalDavAdapter {
} else if name_str == "time-range" || name_str.ends_with(":time-range") { } else if name_str == "time-range" || name_str.ends_with(":time-range") {
// Parse time-range attributes // Parse time-range attributes
for attr in e.attributes().flatten() { for attr in e.attributes().flatten() {
let attr_name = let attr_name = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
let attr_value = attr.unescape_value().unwrap_or_default(); let attr_value = attr.unescape_value().unwrap_or_default();
if attr_name == "start" { if attr_name == "start" {
@@ -60,7 +60,6 @@ impl QualifiedName {
name: name.into(), name: name.into(),
} }
} }
} }
impl std::fmt::Display for QualifiedName { impl std::fmt::Display for QualifiedName {
@@ -118,7 +118,14 @@ impl FileUploadUseCase for FileUploadService {
) -> Result<FileDto, DomainError> { ) -> Result<FileDto, DomainError> {
let file = self let file = self
.file_write .file_write
.save_file_from_temp(name.clone(), folder_id, content_type, temp_path, size, pre_computed_hash) .save_file_from_temp(
name.clone(),
folder_id,
content_type,
temp_path,
size,
pre_computed_hash,
)
.await?; .await?;
let dto = FileDto::from(file); let dto = FileDto::from(file);
info!( info!(
@@ -165,8 +172,15 @@ impl FileUploadUseCase for FileUploadService {
})? })?
.len(); .len();
self.upload_file_streaming(name, folder_id, content_type, file_path, size, pre_computed_hash) self.upload_file_streaming(
.await name,
folder_id,
content_type,
file_path,
size,
pre_computed_hash,
)
.await
} }
/// Creates a file at a specific path (for WebDAV PUT on new resource). /// Creates a file at a specific path (for WebDAV PUT on new resource).
@@ -205,12 +219,13 @@ impl FileUploadUseCase for FileUploadService {
async fn update_file(&self, path: &str, content: &[u8]) -> Result<(), DomainError> { async fn update_file(&self, path: &str, content: &[u8]) -> Result<(), DomainError> {
// Direct SQL lookup — O(folder_depth) instead of O(total_files) // Direct SQL lookup — O(folder_depth) instead of O(total_files)
if let Some(file_read) = &self.file_read if let Some(file_read) = &self.file_read
&& let Some(file) = file_read.find_file_by_path(path).await? { && let Some(file) = file_read.find_file_by_path(path).await?
self.file_write {
.update_file_content(file.id(), content.to_vec()) self.file_write
.await?; .update_file_content(file.id(), content.to_vec())
return Ok(()); .await?;
} return Ok(());
}
let path_normalized = path.trim_start_matches('/').trim_end_matches('/'); let path_normalized = path.trim_start_matches('/').trim_end_matches('/');
let (parent_path, filename) = if let Some(idx) = path_normalized.rfind('/') { let (parent_path, filename) = if let Some(idx) = path_normalized.rfind('/') {
-1
View File
@@ -77,7 +77,6 @@ impl StoragePath {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.segments.is_empty() self.segments.is_empty()
} }
} }
impl std::fmt::Display for StoragePath { impl std::fmt::Display for StoragePath {
@@ -106,7 +106,19 @@ impl FileBlobReadRepository {
#[async_trait] #[async_trait]
impl FileReadPort for FileBlobReadRepository { impl FileReadPort for FileBlobReadRepository {
async fn get_file(&self, id: &str) -> Result<File, DomainError> { async fn get_file(&self, id: &str) -> Result<File, DomainError> {
let row = sqlx::query_as::<_, (String, String, Option<String>, i64, String, i64, i64, String)>( let row = sqlx::query_as::<
_,
(
String,
String,
Option<String>,
i64,
String,
i64,
i64,
String,
),
>(
r#" r#"
SELECT id::text, name, folder_id::text, size, mime_type, SELECT id::text, name, folder_id::text, size, mime_type,
EXTRACT(EPOCH FROM created_at)::bigint, EXTRACT(EPOCH FROM created_at)::bigint,
@@ -374,7 +386,9 @@ impl FileReadPort for FileBlobReadRepository {
.map_err(|e| DomainError::internal_error("FileBlobRead", format!("find file: {e}")))?; .map_err(|e| DomainError::internal_error("FileBlobRead", format!("find file: {e}")))?;
match row { match row {
Some(r) => Ok(Some(self.row_to_file(r.0, r.1, r.2, r.3, r.4, r.5, r.6).await?)), Some(r) => Ok(Some(
self.row_to_file(r.0, r.1, r.2, r.3, r.4, r.5, r.6).await?,
)),
None => Ok(None), None => Ok(None),
} }
} }
@@ -138,12 +138,13 @@ impl FileWritePort for FileBlobWriteRepository {
); );
} }
if let sqlx::Error::Database(ref db_err) = e if let sqlx::Error::Database(ref db_err) = e
&& db_err.code().as_deref() == Some("23505") { && db_err.code().as_deref() == Some("23505")
return Err(DomainError::already_exists( {
"File", return Err(DomainError::already_exists(
format!("{name} already exists in folder"), "File",
)); format!("{name} already exists in folder"),
} ));
}
return Err(DomainError::internal_error( return Err(DomainError::internal_error(
"FileBlobWrite", "FileBlobWrite",
format!("insert: {e}"), format!("insert: {e}"),
@@ -210,12 +211,13 @@ impl FileWritePort for FileBlobWriteRepository {
); );
} }
if let sqlx::Error::Database(ref db_err) = e if let sqlx::Error::Database(ref db_err) = e
&& db_err.code().as_deref() == Some("23505") { && db_err.code().as_deref() == Some("23505")
return Err(DomainError::already_exists( {
"File", return Err(DomainError::already_exists(
format!("{name} already exists in folder"), "File",
)); format!("{name} already exists in folder"),
} ));
}
return Err(DomainError::internal_error( return Err(DomainError::internal_error(
"FileBlobWrite", "FileBlobWrite",
format!("insert: {e}"), format!("insert: {e}"),
@@ -230,8 +232,16 @@ impl FileWritePort for FileBlobWriteRepository {
&blob_hash[..12] &blob_hash[..12]
); );
self.row_to_file(row.0, name, folder_id, size as i64, content_type, row.1, row.2) self.row_to_file(
.await row.0,
name,
folder_id,
size as i64,
content_type,
row.1,
row.2,
)
.await
} }
async fn move_file( async fn move_file(
@@ -312,12 +322,13 @@ impl FileWritePort for FileBlobWriteRepository {
.await .await
.map_err(|e| { .map_err(|e| {
if let sqlx::Error::Database(ref db_err) = e if let sqlx::Error::Database(ref db_err) = e
&& db_err.code().as_deref() == Some("23505") { && db_err.code().as_deref() == Some("23505")
return DomainError::already_exists( {
"File", return DomainError::already_exists(
"File with that name already exists in target folder".to_string(), "File",
); "File with that name already exists in target folder".to_string(),
} );
}
DomainError::internal_error("FileBlobWrite", format!("copy: {e}")) DomainError::internal_error("FileBlobWrite", format!("copy: {e}"))
})? })?
.ok_or_else(|| DomainError::not_found("File", file_id))?; .ok_or_else(|| DomainError::not_found("File", file_id))?;
@@ -360,12 +371,10 @@ impl FileWritePort for FileBlobWriteRepository {
.await .await
.map_err(|e| { .map_err(|e| {
if let sqlx::Error::Database(ref db_err) = e if let sqlx::Error::Database(ref db_err) = e
&& db_err.code().as_deref() == Some("23505") { && db_err.code().as_deref() == Some("23505")
return DomainError::already_exists( {
"File", return DomainError::already_exists("File", format!("{new_name} already exists"));
format!("{new_name} already exists"), }
);
}
DomainError::internal_error("FileBlobWrite", format!("rename: {e}")) DomainError::internal_error("FileBlobWrite", format!("rename: {e}"))
})? })?
.ok_or_else(|| DomainError::not_found("File", file_id))?; .ok_or_else(|| DomainError::not_found("File", file_id))?;
@@ -449,13 +458,14 @@ impl FileWritePort for FileBlobWriteRepository {
// Decrement old blob ref (only if hash changed, best-effort) // Decrement old blob ref (only if hash changed, best-effort)
if old_hash != new_hash if old_hash != new_hash
&& let Err(e) = self.dedup.remove_reference(&old_hash).await { && let Err(e) = self.dedup.remove_reference(&old_hash).await
tracing::warn!( {
"Failed to decrement old blob ref {}: {}", tracing::warn!(
&old_hash[..12], "Failed to decrement old blob ref {}: {}",
e &old_hash[..12],
); e
} );
}
Ok(()) Ok(())
} }
@@ -131,12 +131,13 @@ impl FolderRepository for FolderDbRepository {
.await .await
.map_err(|e| { .map_err(|e| {
if let sqlx::Error::Database(ref db_err) = e if let sqlx::Error::Database(ref db_err) = e
&& db_err.code().as_deref() == Some("23505") { && db_err.code().as_deref() == Some("23505")
return DomainError::already_exists( {
"Folder", return DomainError::already_exists(
format!("{name} already exists in parent"), "Folder",
); format!("{name} already exists in parent"),
} );
}
DomainError::internal_error("FolderDb", format!("insert: {e}")) DomainError::internal_error("FolderDb", format!("insert: {e}"))
})?; })?;
@@ -333,12 +334,10 @@ impl FolderRepository for FolderDbRepository {
.await .await
.map_err(|e| { .map_err(|e| {
if let sqlx::Error::Database(ref db_err) = e if let sqlx::Error::Database(ref db_err) = e
&& db_err.code().as_deref() == Some("23505") { && db_err.code().as_deref() == Some("23505")
return DomainError::already_exists( {
"Folder", return DomainError::already_exists("Folder", format!("{new_name} already exists"));
format!("{new_name} already exists"), }
);
}
DomainError::internal_error("FolderDb", format!("rename: {e}")) DomainError::internal_error("FolderDb", format!("rename: {e}"))
})?; })?;
+25 -20
View File
@@ -215,9 +215,7 @@ impl DedupService {
} }
// Atomic write: temp file → rename // Atomic write: temp file → rename
let temp_path = self let temp_path = self.temp_root.join(format!("{}.tmp", uuid::Uuid::new_v4()));
.temp_root
.join(format!("{}.tmp", uuid::Uuid::new_v4()));
fs::write(&temp_path, content).await.map_err(|e| { fs::write(&temp_path, content).await.map_err(|e| {
DomainError::internal_error("Dedup", format!("Failed to write temp blob: {}", e)) DomainError::internal_error("Dedup", format!("Failed to write temp blob: {}", e))
})?; })?;
@@ -269,10 +267,7 @@ impl DedupService {
let file_size = fs::metadata(source_path) let file_size = fs::metadata(source_path)
.await .await
.map_err(|e| { .map_err(|e| {
DomainError::internal_error( DomainError::internal_error("Dedup", format!("Failed to get file metadata: {}", e))
"Dedup",
format!("Failed to get file metadata: {}", e),
)
})? })?
.len(); .len();
@@ -555,7 +550,10 @@ impl DedupService {
format!("Failed to open blob {}: {}", hash, e), format!("Failed to open blob {}: {}", hash, e),
) )
})?; })?;
Ok(Box::pin(ReaderStream::with_capacity(file, STREAM_CHUNK_SIZE))) Ok(Box::pin(ReaderStream::with_capacity(
file,
STREAM_CHUNK_SIZE,
)))
} }
/// Stream a byte range of a blob — only reads the requested portion. /// Stream a byte range of a blob — only reads the requested portion.
@@ -588,9 +586,15 @@ impl DedupService {
if let Some(end_pos) = end { if let Some(end_pos) = end {
let limit = end_pos.saturating_sub(start); let limit = end_pos.saturating_sub(start);
let limited = file.take(limit); let limited = file.take(limit);
Ok(Box::pin(ReaderStream::with_capacity(limited, STREAM_CHUNK_SIZE))) Ok(Box::pin(ReaderStream::with_capacity(
limited,
STREAM_CHUNK_SIZE,
)))
} else { } else {
Ok(Box::pin(ReaderStream::with_capacity(file, STREAM_CHUNK_SIZE))) Ok(Box::pin(ReaderStream::with_capacity(
file,
STREAM_CHUNK_SIZE,
)))
} }
} }
@@ -680,15 +684,15 @@ impl DedupService {
} }
// Check size // Check size
if let Ok(file_meta) = fs::metadata(&blob_path).await { if let Ok(file_meta) = fs::metadata(&blob_path).await
if file_meta.len() != *expected_size as u64 { && file_meta.len() != *expected_size as u64
corrupted.push(format!( {
"{}: size mismatch (expected: {}, actual: {})", corrupted.push(format!(
hash, "{}: size mismatch (expected: {}, actual: {})",
expected_size, hash,
file_meta.len() expected_size,
)); file_meta.len()
} ));
} }
} }
@@ -756,7 +760,8 @@ impl DedupPort for DedupService {
content_type: Option<String>, content_type: Option<String>,
pre_computed_hash: Option<String>, pre_computed_hash: Option<String>,
) -> Result<DedupResultDto, DomainError> { ) -> Result<DedupResultDto, DomainError> {
self.store_from_file(source_path, content_type, pre_computed_hash).await self.store_from_file(source_path, content_type, pre_computed_hash)
.await
} }
async fn blob_exists(&self, hash: &str) -> bool { async fn blob_exists(&self, hash: &str) -> bool {
@@ -82,7 +82,6 @@ impl FileContentCache {
misses: AtomicUsize::new(0), misses: AtomicUsize::new(0),
} }
} }
} }
impl Default for FileContentCache { impl Default for FileContentCache {
@@ -301,7 +301,13 @@ impl ChunkedUploadHandler {
// Upload from assembled file on disk — zero extra RAM copies, hash pre-computed // Upload from assembled file on disk — zero extra RAM copies, hash pre-computed
match upload_service match upload_service
.upload_file_from_path(filename.clone(), folder_id.clone(), content_type, &assembled_path, Some(hash)) .upload_file_from_path(
filename.clone(),
folder_id.clone(),
content_type,
&assembled_path,
Some(hash),
)
.await .await
{ {
Ok(file) => { Ok(file) => {
+11 -12
View File
@@ -114,7 +114,7 @@ impl FileHandler {
.and_then(|v| v.to_str().ok()) .and_then(|v| v.to_str().ok())
.and_then(|s| s.parse::<u64>().ok()); .and_then(|s| s.parse::<u64>().ok());
if let Some(len) = hint { if let Some(len) = hint {
let _ = file.set_len(len).await; // best-effort let _ = file.set_len(len).await; // best-effort
} }
// 512 KB buffer — 8× fewer write syscalls than 64 KB // 512 KB buffer — 8× fewer write syscalls than 64 KB
@@ -164,15 +164,15 @@ impl FileHandler {
.check_storage_quota(&auth_user.id, total_size) .check_storage_quota(&auth_user.id, total_size)
.await .await
{ {
let _ = tokio::fs::remove_file(&temp_path).await; let _ = tokio::fs::remove_file(&temp_path).await;
tracing::warn!( tracing::warn!(
"⛔ UPLOAD REJECTED (quota): user={}, file={}, size={}", "⛔ UPLOAD REJECTED (quota): user={}, file={}, size={}",
auth_user.username, auth_user.username,
filename, filename,
total_size total_size
); );
return Self::quota_error_response(err).into_response(); return Self::quota_error_response(err).into_response();
} }
// ── Streaming upload (temp file → blob store, hash pre-computed) ─ // ── Streaming upload (temp file → blob store, hash pre-computed) ─
match upload_service match upload_service
@@ -543,8 +543,7 @@ impl FileHandler {
multipart: Multipart, multipart: Multipart,
) -> impl IntoResponse { ) -> impl IntoResponse {
// Use the streaming upload handler // Use the streaming upload handler
let response = let response = Self::upload_file(State(state.clone()), auth_user, multipart).await;
Self::upload_file(State(state.clone()), auth_user, multipart).await;
// Try to extract file info for thumbnail generation // Try to extract file info for thumbnail generation
if let Ok(body_bytes) = if let Ok(body_bytes) =