perf: implement findings #2, #3, #17 from architecture audit

- Finding #2: Replace Mutex<HashMap> with moka::sync::Cache in file_blob_read_repository (10K cap, 30s TTI)
- Finding #3: Add chunked upload persistence with session.json + progress.bin bitmask for crash recovery
- Finding #17: Remove manual gzip compression, delegate entirely to tower-http CompressionLayer
- Remove dead code: StubCompressionPort, GzipCompressionService re-export, duplicate response structs
- All 114 tests passing
This commit is contained in:
Diocrafts
2026-02-22 14:12:53 +01:00
parent 0975f1f7ab
commit fd9e509648
8 changed files with 805 additions and 239 deletions
+12 -56
View File
@@ -10,7 +10,6 @@ use http_range_header::parse_range_header;
use serde::Deserialize;
use std::collections::HashMap;
use crate::application::ports::compression_ports::{CompressionLevel, CompressionPort};
use crate::application::ports::file_ports::OptimizedFileContent;
use crate::common::di::AppState;
use crate::interfaces::middleware::auth::{AuthUser, OptionalUserId};
@@ -464,11 +463,7 @@ impl FileHandler {
&mime_type,
&disposition,
&etag,
file_dto.size,
&params,
&*state.core.compression_service,
)
.await
.into_response(),
OptimizedFileContent::Mmap(mmap_data) => Response::builder()
.status(StatusCode::OK)
@@ -862,69 +857,30 @@ impl FileHandler {
.unwrap()
}
/// Build response for cached/small files with optional compression.
async fn build_cached_response(
/// Build response for cached/small files.
///
/// Compression is handled uniformly by `CompressionLayer` (tower-http)
/// which negotiates `Accept-Encoding` and applies gzip/brotli in streaming
/// mode. No manual compression is done here to avoid double-encoding.
fn build_cached_response(
content: Bytes,
mime_type: &str,
disposition: &str,
etag: &str,
file_size: u64,
params: &HashMap<String, String>,
compression_service: &dyn CompressionPort,
) -> Response<Body> {
let compression_param = params.get("compress").map(|v| v.as_str());
let force_compress = compression_param == Some("true") || compression_param == Some("1");
let force_no_compress =
compression_param == Some("false") || compression_param == Some("0");
let should_compress = if force_no_compress {
false
} else if force_compress {
true
} else {
compression_service.should_compress(mime_type, file_size)
};
let compression_level = match params.get("compression_level").map(|v| v.as_str()) {
Some("fast") => CompressionLevel::Fast,
Some("best") => CompressionLevel::Best,
_ => CompressionLevel::Default,
};
let builder = Response::builder()
Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, mime_type)
.header(header::CONTENT_DISPOSITION, disposition)
.header(header::ETAG, etag)
.header(
header::CACHE_CONTROL,
"private, max-age=3600, must-revalidate",
)
.header(header::VARY, "Accept-Encoding");
if should_compress {
match compression_service
.compress_data(&content, compression_level)
.await
{
Ok(compressed) => builder
.header(header::CONTENT_TYPE, mime_type)
.header(header::CONTENT_ENCODING, "gzip")
.header(header::CONTENT_LENGTH, compressed.len())
.body(Body::from(compressed))
.unwrap(),
Err(_) => builder
.header(header::CONTENT_TYPE, mime_type)
.header(header::CONTENT_LENGTH, content.len())
.body(Body::from(content))
.unwrap(),
}
} else {
builder
.header(header::CONTENT_TYPE, mime_type)
.header(header::CONTENT_LENGTH, content.len())
.body(Body::from(content))
.unwrap()
}
.header(header::VARY, "Accept-Encoding")
.header(header::CONTENT_LENGTH, content.len())
.body(Body::from(content))
.unwrap()
}
}