f2d35ca792
- JWT secret auto-generates and persists to <STORAGE_PATH>/.jwt_secret - Remove setup token: first admin setup is open until system initialized - Fix schema.sql: move CREATE EXTENSION pg_trgm/ltree to top - Update login UI and auth.js to remove setup token fields
2.9 KiB
Executable File
2.9 KiB
Executable File
10 - ZIP and Compression
Two compression features exist: ZIP download (download folders as ZIP archives) and Gzip compression (transparent gzip for file content responses).
ZIP Download
Architecture
| Layer | Component | File |
|---|---|---|
| Application Port | ZipPort trait | src/application/ports/zip_ports.rs |
| Infrastructure | ZipService | src/infrastructure/services/zip_service.rs |
| Interfaces | FolderHandler::download_folder_zip |
src/interfaces/api/handlers/folder_handler.rs |
REST API
| Method | Path | Description |
|---|---|---|
GET |
/api/folders/{id}/download |
Download folder as ZIP archive |
Implementation
- Compression method:
Deflatedvia thezipcrate - Traversal: iterative work-queue pattern (not recursive async) using a PendingFolder struct
- Cycle detection:
HashSet<String>of processed folder IDs - ZIP is built entirely in-memory (
ZipWriter<Cursor<Vec<u8>>>) - UNIX permissions:
0o755for all entries
Port Trait
#[async_trait]
pub trait ZipPort: Send + Sync + 'static {
async fn create_folder_zip(&self, folder_id: &str, folder_name: &str) -> Result<Vec<u8>, DomainError>;
}
Example
curl -H "Authorization: Bearer $TOKEN" \
"https://oxicloud.example.com/api/folders/abc-123/download" \
-o my-folder.zip
Gzip Compression
Architecture
| Layer | Component | File |
|---|---|---|
| Application Port | CompressionPort trait | src/application/ports/compression_ports.rs |
| Infrastructure | GzipCompressionService | src/infrastructure/services/compression_service.rs |
Configuration
| Constant | Value | Description |
|---|---|---|
COMPRESSION_SIZE_THRESHOLD |
50 KB | Files below this are never compressed |
Compression Levels
pub enum CompressionLevel {
None = 0,
Fast = 1,
Default = 6,
Best = 9,
}
Port Trait
#[async_trait]
pub trait CompressionPort: Send + Sync + 'static {
async fn compress_data(&self, data: &[u8], level: CompressionLevel) -> Result<Vec<u8>, DomainError>;
async fn decompress_data(&self, compressed_data: &[u8]) -> Result<Vec<u8>, DomainError>;
fn should_compress(&self, mime_type: &str, size: u64) -> bool;
}
Skip List
These MIME types are never compressed (already compressed or binary):
image/*(exceptsvg,bmp)audio/*,video/*application/zip,application/gzip,application/x-compressedapplication/x-7z-compressed,application/x-rar-compressedapplication/x-bzip2,application/x-xz
Implementation Details
- Uses the
flate2crate (GzEncoder/GzDecoder) - Compress/decompress run inside
spawn_blockingto avoid blocking the async runtime - Optional BufferPool integration for buffer reuse
- Buffer pool estimates: 80% of input size for compression, 5x for decompression