summaryrefslogtreecommitdiff
path: root/rola-bucket/src/protocol.rs
blob: 949e6d4e08c5ba25d97b67e04dec320ee9b49551 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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) }
    }
}