diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-18 00:46:20 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-18 00:46:20 +0800 |
| commit | 330e5ed096cfde3eb6217d4364ee62b92c97c826 (patch) | |
| tree | f9aa4c8106b193160de272784d85392efcd965ac /rola-bucket | |
| parent | 346eefc2ccfc06a133dafaa4fb86f1e21599179d (diff) | |
feat(rola-bucket): add bucket transfer protocol and error handling
Diffstat (limited to 'rola-bucket')
| -rw-r--r-- | rola-bucket/Cargo.toml | 3 | ||||
| -rw-r--r-- | rola-bucket/src/bucket.rs | 0 | ||||
| -rw-r--r-- | rola-bucket/src/lib.rs | 15 | ||||
| -rw-r--r-- | rola-bucket/src/protocol.rs | 169 | ||||
| -rw-r--r-- | rola-bucket/src/protocol/error.rs | 19 |
5 files changed, 206 insertions, 0 deletions
diff --git a/rola-bucket/Cargo.toml b/rola-bucket/Cargo.toml index 85d7fab..001ec11 100644 --- a/rola-bucket/Cargo.toml +++ b/rola-bucket/Cargo.toml @@ -6,3 +6,6 @@ authors.workspace = true license.workspace = true [dependencies] +shared_functions.workspace = true +shared_macros.workspace = true +thiserror.workspace = true diff --git a/rola-bucket/src/bucket.rs b/rola-bucket/src/bucket.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/rola-bucket/src/bucket.rs diff --git a/rola-bucket/src/lib.rs b/rola-bucket/src/lib.rs index 8b13789..c45452c 100644 --- a/rola-bucket/src/lib.rs +++ b/rola-bucket/src/lib.rs @@ -1 +1,16 @@ +//! Rorolala Bucket +//! +//! # Introduction +//! +//! `Bucket` is the central repository in **Rola** for storing files. It stores: +//! - **Delta Fragment**: Stores incremental data of a file, friendly to uncompressed sequential large files; the actual content can be computed via an index. +//! - **Full Storage**: Stores a complete file, data can be retrieved directly via an index. +//! - **Compressed Storage**: Stores a compressed complete file, data can be retrieved directly via an index. +//! - **Limited Storage**: Stores a limited number of recent versions according to rules (maximum size, maximum number of versions); only the **existing** data can be retrieved directly via an index. +//! +//! # Interface Boundary +//! +//! This module does **not** implement any **specific transport method**; it only implements the workflow for file storage and retrieval. +mod protocol; +pub use protocol::*; diff --git a/rola-bucket/src/protocol.rs b/rola-bucket/src/protocol.rs new file mode 100644 index 0000000..949e6d4 --- /dev/null +++ b/rola-bucket/src/protocol.rs @@ -0,0 +1,169 @@ +use std::path::Path; + +mod error; +pub use error::*; + +/// Request used in [BucketTransferProtocol] or [AsyncBucketTransferProtocol] +pub struct UploadToBucketRequest<'a, Info> +where + Info: Clone + Sync + Send, +{ + /// Extra data to record during the transfer process + pub extra_info: &'a Info, + + /// The relative file path in the bucket to store the uploaded file + pub relative_file_path_to_receive: &'a Path, + + /// The absolute file path of the file to be uploaded to the remote bucket + pub absolute_file_path_to_upload: &'a Path, +} + +/// Request used in [BucketTransferProtocol] or [AsyncBucketTransferProtocol] +pub struct DownloadFromBucketRequest<'a, Info> +where + Info: Clone + Sync + Send, +{ + /// Extra data to record during the transfer process + pub extra_info: &'a Info, + + /// The relative file path in the bucket to download + pub relative_file_path_to_transfer: &'a Path, + + /// The absolute file path to download the file to locally + pub absolute_file_path_to_download: &'a Path, +} + +/// Request used in [BucketTransferProtocol] or [AsyncBucketTransferProtocol] +pub struct TransferToClientRequest<'a, Info> +where + Info: Clone + Sync + Send, +{ + /// Extra data to record during the transfer process + pub extra_info: &'a Info, + + /// The relative file path for the client to download from the bucket + pub relative_file_path_to_download: &'a Path, + + /// The absolute file path of the file to be transferred to the client + pub absolute_file_path_to_transfer: &'a Path, +} + +/// Request used in [BucketTransferProtocol] or [AsyncBucketTransferProtocol] +pub struct ReceiveFromClientRequest<'a, Info> +where + Info: Clone + Sync + Send, +{ + /// Extra data to record during the transfer process + pub extra_info: &'a Info, + + /// The relative file path in the bucket to store the uploaded file + pub relative_file_path_to_upload: &'a Path, + + /// The absolute file path to download the file to locally + pub absolute_file_path_to_receive: &'a Path, +} + +/// This trait is used to implement the specific workflow of file transfer +pub trait BucketTransferProtocol { + /// Structure used to record transfer information + type TransferInfo: Clone + Sync + Send; + + /// Upload a file to the storage bucket + /// The caller must ensure that this function performs the actual transfer operation + fn upload_to_bucket( + &self, + req: &UploadToBucketRequest<Self::TransferInfo>, + ) -> Result<(), BucketTransferProtocolError>; + + /// Download a file from the storage bucket + /// The caller must ensure that after this function executes, a file (and only a file, not a directory) exists at the `path_to_save_file` path + fn download_from_bucket( + &self, + req: &DownloadFromBucketRequest<Self::TransferInfo>, + ) -> Result<(), BucketTransferProtocolError>; + + /// Transfer a file to the client + /// The caller must ensure that this function performs the actual transfer operation + fn transfer_to_client( + &self, + req: &TransferToClientRequest<Self::TransferInfo>, + ) -> Result<(), BucketTransferProtocolError>; + + /// Receive a file from the client + /// The caller must ensure that after this function executes, a file (and only a file, not a directory) exists at the `path_to_save_file` path + fn receive_from_client( + &self, + req: &ReceiveFromClientRequest<Self::TransferInfo>, + ) -> Result<(), BucketTransferProtocolError>; +} + +/// This trait is used to implement the specific workflow of file transfer (asynchronous mode) +pub trait AsyncBucketTransferProtocol { + /// Structure used to record transfer information + type TransferInfo: Clone + Sync + Send; + + /// Asynchronously upload a file to the storage bucket + /// The caller must ensure that this function performs the actual transfer operation + fn upload_to_bucket_async( + &self, + req: &UploadToBucketRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync; + + /// Asynchronously download a file from the storage bucket + /// The caller must ensure that after this function executes, a file (and only a file, not a directory) exists at the `path_to_save_file` path + fn download_from_bucket_async( + &self, + req: &DownloadFromBucketRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync; + + /// Asynchronously transfer a file to the client + /// The caller must ensure that this function performs the actual transfer operation + fn transfer_to_client_async( + &self, + req: &TransferToClientRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync; + + /// Asynchronously receive a file from the client + /// The caller must ensure that after this function executes, a file (and only a file, not a directory) exists at the `path_to_save_file` path + fn receive_from_client_async( + &self, + req: &ReceiveFromClientRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync; +} + +/// Blanket implementation: automatically provides async versions of all +/// `BucketTransferProtocol` methods by wrapping them in `async {}` blocks. +impl<T: BucketTransferProtocol + Sync> AsyncBucketTransferProtocol for T +where + T::TransferInfo: Sync, +{ + type TransferInfo = T::TransferInfo; + + fn upload_to_bucket_async( + &self, + req: &UploadToBucketRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync { + async move { self.upload_to_bucket(req) } + } + + fn download_from_bucket_async( + &self, + req: &DownloadFromBucketRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync { + async move { self.download_from_bucket(req) } + } + + fn transfer_to_client_async( + &self, + req: &TransferToClientRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync { + async move { self.transfer_to_client(req) } + } + + fn receive_from_client_async( + &self, + req: &ReceiveFromClientRequest<Self::TransferInfo>, + ) -> impl Future<Output = Result<(), BucketTransferProtocolError>> + Send + Sync { + async move { self.receive_from_client(req) } + } +} diff --git a/rola-bucket/src/protocol/error.rs b/rola-bucket/src/protocol/error.rs new file mode 100644 index 0000000..95447f7 --- /dev/null +++ b/rola-bucket/src/protocol/error.rs @@ -0,0 +1,19 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum BucketTransferProtocolError { + #[error("network connection failed: {0}")] + NetworkError(#[source] std::io::Error), + + #[error("authentication failed: {0}")] + AuthenticationError(String), + + #[error("permission denied: {0}")] + PermissionDenied(String), + + #[error("I/O error: {0}")] + IoError(#[source] std::io::Error), + + #[error("timeout occurred")] + Timeout, +} |
