P1: AsyncS3Vfs implementation (Phase 3)
Some checks failed
Test / build (push) Has been cancelled
Test / test (push) Has been cancelled

- AsyncS3Vfs: spawn_blocking wrapper over S3Vfs
- AsyncS3File: tokio::sync::Mutex for async state
- Add Clone derive to S3Vfs
- All backend methods wrapped with spawn_blocking

Phase 3 complete: AsyncS3Vfs working
Phase 4 pending: AsyncSmbVfs
Phase 5 pending: WebDAV integration

Tests: 293 passed, 0 failed
This commit is contained in:
Warren
2026-06-21 21:08:48 +08:00
parent 790efe13f4
commit 5c9b51fc49
3 changed files with 294 additions and 0 deletions

View File

@@ -8,6 +8,7 @@ use std::time::{Duration, SystemTime};
use url::Url;
/// S3-compatible 文件系統後端
#[derive(Clone)]
pub struct S3Vfs {
bucket: Bucket,
credentials: Credentials,
@@ -417,6 +418,28 @@ impl VfsBackend for S3Vfs {
let to_key = Self::path_to_key(link);
self.copy_object(&from_key, &to_key)
}
fn copy(&self, from: &Path, to: &Path) -> Result<(), VfsError> {
let from_key = Self::path_to_key(from);
let to_key = Self::path_to_key(to);
// Check if source is a directory marker
if from.ends_with("/") || from_key.ends_with('/') {
// Directory copy: create destination directory marker
let action = actions::PutObject::new(&self.bucket, Some(&self.credentials), &to_key);
let url = action.sign(Duration::from_secs(3600));
ureq::put(url.as_str())
.send_bytes(&[])
.map_err(|e| VfsError::Io(format!("S3 PutObject failed: {}", e)))?;
return Ok(());
}
// Try HeadObject to verify source exists
match self.head_object(&from_key) {
Ok(_) => self.copy_object(&from_key, &to_key),
Err(e) => Err(e),
}
}
}
impl VfsFile for S3VfsFile {