summaryrefslogtreecommitdiff
path: root/rola-bucket/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-18 00:46:20 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-18 00:46:20 +0800
commit330e5ed096cfde3eb6217d4364ee62b92c97c826 (patch)
treef9aa4c8106b193160de272784d85392efcd965ac /rola-bucket/src
parent346eefc2ccfc06a133dafaa4fb86f1e21599179d (diff)
feat(rola-bucket): add bucket transfer protocol and error handling
Diffstat (limited to 'rola-bucket/src')
-rw-r--r--rola-bucket/src/bucket.rs0
-rw-r--r--rola-bucket/src/lib.rs15
-rw-r--r--rola-bucket/src/protocol.rs169
-rw-r--r--rola-bucket/src/protocol/error.rs19
4 files changed, 203 insertions, 0 deletions
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,
+}