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") {
|
} 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,7 +172,14 @@ 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(
|
||||||
|
name,
|
||||||
|
folder_id,
|
||||||
|
content_type,
|
||||||
|
file_path,
|
||||||
|
size,
|
||||||
|
pre_computed_hash,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +219,8 @@ 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
|
self.file_write
|
||||||
.update_file_content(file.id(), content.to_vec())
|
.update_file_content(file.id(), content.to_vec())
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@@ -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,7 +138,8 @@ 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(
|
return Err(DomainError::already_exists(
|
||||||
"File",
|
"File",
|
||||||
format!("{name} already exists in folder"),
|
format!("{name} already exists in folder"),
|
||||||
@@ -210,7 +211,8 @@ 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(
|
return Err(DomainError::already_exists(
|
||||||
"File",
|
"File",
|
||||||
format!("{name} already exists in folder"),
|
format!("{name} already exists in folder"),
|
||||||
@@ -230,7 +232,15 @@ 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(
|
||||||
|
row.0,
|
||||||
|
name,
|
||||||
|
folder_id,
|
||||||
|
size as i64,
|
||||||
|
content_type,
|
||||||
|
row.1,
|
||||||
|
row.2,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +322,8 @@ 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(
|
return DomainError::already_exists(
|
||||||
"File",
|
"File",
|
||||||
"File with that name already exists in target folder".to_string(),
|
"File with that name already exists in target folder".to_string(),
|
||||||
@@ -360,11 +371,9 @@ 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}"))
|
||||||
})?
|
})?
|
||||||
@@ -449,7 +458,8 @@ 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!(
|
tracing::warn!(
|
||||||
"Failed to decrement old blob ref {}: {}",
|
"Failed to decrement old blob ref {}: {}",
|
||||||
&old_hash[..12],
|
&old_hash[..12],
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ 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(
|
return DomainError::already_exists(
|
||||||
"Folder",
|
"Folder",
|
||||||
format!("{name} already exists in parent"),
|
format!("{name} already exists in parent"),
|
||||||
@@ -333,11 +334,9 @@ 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}"))
|
||||||
})?;
|
})?;
|
||||||
|
|||||||
@@ -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,8 +684,9 @@ 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!(
|
corrupted.push(format!(
|
||||||
"{}: size mismatch (expected: {}, actual: {})",
|
"{}: size mismatch (expected: {}, actual: {})",
|
||||||
hash,
|
hash,
|
||||||
@@ -690,7 +695,6 @@ impl DedupService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if corrupted.is_empty() {
|
if corrupted.is_empty() {
|
||||||
tracing::info!("Integrity check passed for {} blobs", rows.len());
|
tracing::info!("Integrity check passed for {} blobs", rows.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) => {
|
||||||
|
|||||||
@@ -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) =
|
||||||
|
|||||||
Reference in New Issue
Block a user