1use crate::deta_client::DetaClient;
5pub mod models;
6mod requests;
7use crate::constants;
8use crate::error::Result;
9use crate::utils;
10
11pub struct Drive {
14 base_url: String,
15 x_api_key: String,
16}
17
18impl Drive {
19 pub fn new(client: &DetaClient, drive_name: &str) -> Self {
21 let base_url = format!(
22 "{}/{}/{}",
23 constants::DRIVE_API_URL,
24 client.project_id(),
25 drive_name
26 );
27
28 let x_api_key = client.api_key().to_owned();
29
30 Self {
31 base_url,
32 x_api_key,
33 }
34 }
35
36 async fn get_chunked_upload_object(
37 &self,
38 name: &str,
39 ) -> Result<models::InitializeChunkedUpload> {
40 let response =
41 requests::initialize_chunked_upload_request(&self.base_url, &self.x_api_key, name)
42 .await?;
43 Ok(utils::parse_response_body(response).await?)
44 }
45
46 async fn perform_chunked_upload(
47 &self,
48 name: &str,
49 data: Vec<u8>,
50 ) -> Result<models::EndChunkedUpload> {
51 let bytes: bytes::Bytes = data.into();
52 let upload_id = self.get_chunked_upload_object(name).await?.upload_id;
53 let content_length = bytes.len();
54 let chunk_size = constants::MAX_DATA_CHUNK_SIZE;
55 let mut part = 1;
56
57 for idx in (0..content_length).step_by(chunk_size) {
58 let end = content_length.min(idx + chunk_size);
59 let chunk = bytes.slice(idx..end);
60 let upload_result = requests::upload_chunk_request(
61 &self.base_url,
62 &self.x_api_key,
63 name,
64 &upload_id,
65 part,
66 chunk,
67 )
68 .await;
69 if let Err(error) = upload_result {
70 requests::abort_chunked_upload_request(
71 &self.base_url,
72 &self.x_api_key,
73 name,
74 &upload_id,
75 )
76 .await?;
77 return Err(error);
78 }
79 part += 1;
80 }
81
82 let response =
83 requests::end_chunked_upload_request(&self.base_url, &self.x_api_key, name, &upload_id)
84 .await?;
85 Ok(utils::parse_response_body(response).await?)
86 }
87
88 pub async fn put_file(
91 &self,
92 name: &str,
93 data: Vec<u8>,
94 content_type: Option<&str>,
95 ) -> Result<PutFileResult> {
96 if data.len() <= constants::MAX_DATA_CHUNK_SIZE {
97 let response = requests::put_file_request(
98 &self.base_url,
99 &self.x_api_key,
100 name,
101 data,
102 content_type,
103 )
104 .await?;
105 return Ok(PutFileResult::SinglePut(
106 utils::parse_response_body(response).await?,
107 ));
108 }
109
110 Ok(PutFileResult::ChunkedUpload(
111 self.perform_chunked_upload(name, data).await?,
112 ))
113 }
114
115 pub async fn get_file_as_buffer(&self, name: &str) -> Result<Option<bytes::Bytes>> {
117 let response_result =
118 requests::get_file_request(&self.base_url, &self.x_api_key, name).await;
119
120 if let Err(ref error) = response_result {
121 if error.is_not_found() {
122 return Ok(None);
123 }
124 }
125
126 let response = response_result?;
127 let bytes = response.bytes().await?;
128 Ok(Some(bytes))
129 }
130
131 pub async fn get_file_as_u8_vec(&self, name: &str) -> Result<Option<Vec<u8>>> {
133 let bytes = self.get_file_as_buffer(name).await?;
134 if bytes.is_none() {
135 return Ok(None);
136 }
137 let bytes = bytes.unwrap();
138 Ok(Some(bytes.to_vec()))
139 }
140
141 pub async fn list_files(
143 &self,
144 limit: Option<u32>,
145 prefix: Option<&str>,
146 last_name: Option<&str>,
147 ) -> Result<models::ListFiles> {
148 let response =
149 requests::list_files_request(&self.base_url, &self.x_api_key, limit, prefix, last_name)
150 .await?;
151 return Ok(utils::parse_response_body(response).await?);
152 }
153
154 pub async fn delete_files(&self, names: &[String]) -> Result<models::DeleteFiles> {
156 let response =
157 requests::delete_files_request(&self.base_url, &self.x_api_key, names).await?;
158 return Ok(utils::parse_response_body(response).await?);
159 }
160}
161
162#[derive(Debug, Clone)]
165pub enum PutFileResult {
166 SinglePut(models::PutFile),
168 ChunkedUpload(models::EndChunkedUpload),
170}