style: fix clippy collapsible_if + cargo fmt
This commit is contained in:
@@ -150,8 +150,7 @@ impl CalDavAdapter {
|
||||
} else if name_str == "time-range" || name_str.ends_with(":time-range") {
|
||||
// Parse time-range attributes
|
||||
for attr in e.attributes().flatten() {
|
||||
let attr_name =
|
||||
std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
|
||||
let attr_name = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
|
||||
let attr_value = attr.unescape_value().unwrap_or_default();
|
||||
|
||||
if attr_name == "start" {
|
||||
|
||||
@@ -60,7 +60,6 @@ impl QualifiedName {
|
||||
name: name.into(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl std::fmt::Display for QualifiedName {
|
||||
|
||||
@@ -118,7 +118,14 @@ impl FileUploadUseCase for FileUploadService {
|
||||
) -> Result<FileDto, DomainError> {
|
||||
let file = self
|
||||
.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?;
|
||||
let dto = FileDto::from(file);
|
||||
info!(
|
||||
@@ -165,8 +172,15 @@ impl FileUploadUseCase for FileUploadService {
|
||||
})?
|
||||
.len();
|
||||
|
||||
self.upload_file_streaming(name, folder_id, content_type, file_path, size, pre_computed_hash)
|
||||
.await
|
||||
self.upload_file_streaming(
|
||||
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).
|
||||
@@ -205,12 +219,13 @@ impl FileUploadUseCase for FileUploadService {
|
||||
async fn update_file(&self, path: &str, content: &[u8]) -> Result<(), DomainError> {
|
||||
// Direct SQL lookup — O(folder_depth) instead of O(total_files)
|
||||
if let Some(file_read) = &self.file_read
|
||||
&& let Some(file) = file_read.find_file_by_path(path).await? {
|
||||
self.file_write
|
||||
.update_file_content(file.id(), content.to_vec())
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
&& let Some(file) = file_read.find_file_by_path(path).await?
|
||||
{
|
||||
self.file_write
|
||||
.update_file_content(file.id(), content.to_vec())
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path_normalized = path.trim_start_matches('/').trim_end_matches('/');
|
||||
let (parent_path, filename) = if let Some(idx) = path_normalized.rfind('/') {
|
||||
|
||||
@@ -77,7 +77,6 @@ impl StoragePath {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.segments.is_empty()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl std::fmt::Display for StoragePath {
|
||||
|
||||
@@ -106,7 +106,19 @@ impl FileBlobReadRepository {
|
||||
#[async_trait]
|
||||
impl FileReadPort for FileBlobReadRepository {
|
||||
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#"
|
||||
SELECT id::text, name, folder_id::text, size, mime_type,
|
||||
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}")))?;
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,12 +138,13 @@ impl FileWritePort for FileBlobWriteRepository {
|
||||
);
|
||||
}
|
||||
if let sqlx::Error::Database(ref db_err) = e
|
||||
&& db_err.code().as_deref() == Some("23505") {
|
||||
return Err(DomainError::already_exists(
|
||||
"File",
|
||||
format!("{name} already exists in folder"),
|
||||
));
|
||||
}
|
||||
&& db_err.code().as_deref() == Some("23505")
|
||||
{
|
||||
return Err(DomainError::already_exists(
|
||||
"File",
|
||||
format!("{name} already exists in folder"),
|
||||
));
|
||||
}
|
||||
return Err(DomainError::internal_error(
|
||||
"FileBlobWrite",
|
||||
format!("insert: {e}"),
|
||||
@@ -210,12 +211,13 @@ impl FileWritePort for FileBlobWriteRepository {
|
||||
);
|
||||
}
|
||||
if let sqlx::Error::Database(ref db_err) = e
|
||||
&& db_err.code().as_deref() == Some("23505") {
|
||||
return Err(DomainError::already_exists(
|
||||
"File",
|
||||
format!("{name} already exists in folder"),
|
||||
));
|
||||
}
|
||||
&& db_err.code().as_deref() == Some("23505")
|
||||
{
|
||||
return Err(DomainError::already_exists(
|
||||
"File",
|
||||
format!("{name} already exists in folder"),
|
||||
));
|
||||
}
|
||||
return Err(DomainError::internal_error(
|
||||
"FileBlobWrite",
|
||||
format!("insert: {e}"),
|
||||
@@ -230,8 +232,16 @@ impl FileWritePort for FileBlobWriteRepository {
|
||||
&blob_hash[..12]
|
||||
);
|
||||
|
||||
self.row_to_file(row.0, name, folder_id, size as i64, content_type, row.1, row.2)
|
||||
.await
|
||||
self.row_to_file(
|
||||
row.0,
|
||||
name,
|
||||
folder_id,
|
||||
size as i64,
|
||||
content_type,
|
||||
row.1,
|
||||
row.2,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn move_file(
|
||||
@@ -312,12 +322,13 @@ impl FileWritePort for FileBlobWriteRepository {
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if let sqlx::Error::Database(ref db_err) = e
|
||||
&& db_err.code().as_deref() == Some("23505") {
|
||||
return DomainError::already_exists(
|
||||
"File",
|
||||
"File with that name already exists in target folder".to_string(),
|
||||
);
|
||||
}
|
||||
&& db_err.code().as_deref() == Some("23505")
|
||||
{
|
||||
return DomainError::already_exists(
|
||||
"File",
|
||||
"File with that name already exists in target folder".to_string(),
|
||||
);
|
||||
}
|
||||
DomainError::internal_error("FileBlobWrite", format!("copy: {e}"))
|
||||
})?
|
||||
.ok_or_else(|| DomainError::not_found("File", file_id))?;
|
||||
@@ -360,12 +371,10 @@ impl FileWritePort for FileBlobWriteRepository {
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if let sqlx::Error::Database(ref db_err) = e
|
||||
&& db_err.code().as_deref() == Some("23505") {
|
||||
return DomainError::already_exists(
|
||||
"File",
|
||||
format!("{new_name} already exists"),
|
||||
);
|
||||
}
|
||||
&& db_err.code().as_deref() == Some("23505")
|
||||
{
|
||||
return DomainError::already_exists("File", format!("{new_name} already exists"));
|
||||
}
|
||||
DomainError::internal_error("FileBlobWrite", format!("rename: {e}"))
|
||||
})?
|
||||
.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)
|
||||
if old_hash != new_hash
|
||||
&& let Err(e) = self.dedup.remove_reference(&old_hash).await {
|
||||
tracing::warn!(
|
||||
"Failed to decrement old blob ref {}: {}",
|
||||
&old_hash[..12],
|
||||
e
|
||||
);
|
||||
}
|
||||
&& let Err(e) = self.dedup.remove_reference(&old_hash).await
|
||||
{
|
||||
tracing::warn!(
|
||||
"Failed to decrement old blob ref {}: {}",
|
||||
&old_hash[..12],
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -131,12 +131,13 @@ impl FolderRepository for FolderDbRepository {
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if let sqlx::Error::Database(ref db_err) = e
|
||||
&& db_err.code().as_deref() == Some("23505") {
|
||||
return DomainError::already_exists(
|
||||
"Folder",
|
||||
format!("{name} already exists in parent"),
|
||||
);
|
||||
}
|
||||
&& db_err.code().as_deref() == Some("23505")
|
||||
{
|
||||
return DomainError::already_exists(
|
||||
"Folder",
|
||||
format!("{name} already exists in parent"),
|
||||
);
|
||||
}
|
||||
DomainError::internal_error("FolderDb", format!("insert: {e}"))
|
||||
})?;
|
||||
|
||||
@@ -333,12 +334,10 @@ impl FolderRepository for FolderDbRepository {
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if let sqlx::Error::Database(ref db_err) = e
|
||||
&& db_err.code().as_deref() == Some("23505") {
|
||||
return DomainError::already_exists(
|
||||
"Folder",
|
||||
format!("{new_name} already exists"),
|
||||
);
|
||||
}
|
||||
&& db_err.code().as_deref() == Some("23505")
|
||||
{
|
||||
return DomainError::already_exists("Folder", format!("{new_name} already exists"));
|
||||
}
|
||||
DomainError::internal_error("FolderDb", format!("rename: {e}"))
|
||||
})?;
|
||||
|
||||
|
||||
@@ -215,9 +215,7 @@ impl DedupService {
|
||||
}
|
||||
|
||||
// Atomic write: temp file → rename
|
||||
let temp_path = self
|
||||
.temp_root
|
||||
.join(format!("{}.tmp", uuid::Uuid::new_v4()));
|
||||
let temp_path = self.temp_root.join(format!("{}.tmp", uuid::Uuid::new_v4()));
|
||||
fs::write(&temp_path, content).await.map_err(|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)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DomainError::internal_error(
|
||||
"Dedup",
|
||||
format!("Failed to get file metadata: {}", e),
|
||||
)
|
||||
DomainError::internal_error("Dedup", format!("Failed to get file metadata: {}", e))
|
||||
})?
|
||||
.len();
|
||||
|
||||
@@ -555,7 +550,10 @@ impl DedupService {
|
||||
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.
|
||||
@@ -588,9 +586,15 @@ impl DedupService {
|
||||
if let Some(end_pos) = end {
|
||||
let limit = end_pos.saturating_sub(start);
|
||||
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 {
|
||||
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
|
||||
if let Ok(file_meta) = fs::metadata(&blob_path).await {
|
||||
if file_meta.len() != *expected_size as u64 {
|
||||
corrupted.push(format!(
|
||||
"{}: size mismatch (expected: {}, actual: {})",
|
||||
hash,
|
||||
expected_size,
|
||||
file_meta.len()
|
||||
));
|
||||
}
|
||||
if let Ok(file_meta) = fs::metadata(&blob_path).await
|
||||
&& file_meta.len() != *expected_size as u64
|
||||
{
|
||||
corrupted.push(format!(
|
||||
"{}: size mismatch (expected: {}, actual: {})",
|
||||
hash,
|
||||
expected_size,
|
||||
file_meta.len()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,7 +760,8 @@ impl DedupPort for DedupService {
|
||||
content_type: Option<String>,
|
||||
pre_computed_hash: Option<String>,
|
||||
) -> 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 {
|
||||
|
||||
@@ -82,7 +82,6 @@ impl FileContentCache {
|
||||
misses: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Default for FileContentCache {
|
||||
|
||||
@@ -301,7 +301,13 @@ impl ChunkedUploadHandler {
|
||||
|
||||
// Upload from assembled file on disk — zero extra RAM copies, hash pre-computed
|
||||
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
|
||||
{
|
||||
Ok(file) => {
|
||||
|
||||
@@ -114,7 +114,7 @@ impl FileHandler {
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.and_then(|s| s.parse::<u64>().ok());
|
||||
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
|
||||
@@ -164,15 +164,15 @@ impl FileHandler {
|
||||
.check_storage_quota(&auth_user.id, total_size)
|
||||
.await
|
||||
{
|
||||
let _ = tokio::fs::remove_file(&temp_path).await;
|
||||
tracing::warn!(
|
||||
"⛔ UPLOAD REJECTED (quota): user={}, file={}, size={}",
|
||||
auth_user.username,
|
||||
filename,
|
||||
total_size
|
||||
);
|
||||
return Self::quota_error_response(err).into_response();
|
||||
}
|
||||
let _ = tokio::fs::remove_file(&temp_path).await;
|
||||
tracing::warn!(
|
||||
"⛔ UPLOAD REJECTED (quota): user={}, file={}, size={}",
|
||||
auth_user.username,
|
||||
filename,
|
||||
total_size
|
||||
);
|
||||
return Self::quota_error_response(err).into_response();
|
||||
}
|
||||
|
||||
// ── Streaming upload (temp file → blob store, hash pre-computed) ─
|
||||
match upload_service
|
||||
@@ -543,8 +543,7 @@ impl FileHandler {
|
||||
multipart: Multipart,
|
||||
) -> impl IntoResponse {
|
||||
// Use the streaming upload handler
|
||||
let response =
|
||||
Self::upload_file(State(state.clone()), auth_user, multipart).await;
|
||||
let response = Self::upload_file(State(state.clone()), auth_user, multipart).await;
|
||||
|
||||
// Try to extract file info for thumbnail generation
|
||||
if let Ok(body_bytes) =
|
||||
|
||||
Reference in New Issue
Block a user