use crate::deta_client::DetaClient;
pub mod models;
mod requests;
use crate::constants;
use crate::error::Result;
use crate::utils;
pub struct Drive {
base_url: String,
x_api_key: String,
}
impl Drive {
pub fn new(client: &DetaClient, drive_name: &str) -> Self {
let base_url = format!(
"{}/{}/{}",
constants::DRIVE_API_URL,
client.project_id(),
drive_name
);
let x_api_key = client.api_key().to_owned();
Self {
base_url,
x_api_key,
}
}
async fn get_chunked_upload_object(
&self,
name: &str,
) -> Result<models::InitializeChunkedUpload> {
let response =
requests::initialize_chunked_upload_request(&self.base_url, &self.x_api_key, name)
.await?;
Ok(utils::parse_response_body(response).await?)
}
async fn perform_chunked_upload(
&self,
name: &str,
data: Vec<u8>,
) -> Result<models::EndChunkedUpload> {
let bytes: bytes::Bytes = data.into();
let upload_id = self.get_chunked_upload_object(name).await?.upload_id;
let content_length = bytes.len();
let chunk_size = constants::MAX_DATA_CHUNK_SIZE;
let mut part = 1;
for idx in (0..content_length).step_by(chunk_size) {
let end = content_length.min(idx + chunk_size);
let chunk = bytes.slice(idx..end);
let upload_result = requests::upload_chunk_request(
&self.base_url,
&self.x_api_key,
name,
&upload_id,
part,
chunk,
)
.await;
if let Err(error) = upload_result {
requests::abort_chunked_upload_request(
&self.base_url,
&self.x_api_key,
name,
&upload_id,
)
.await?;
return Err(error);
}
part += 1;
}
let response =
requests::end_chunked_upload_request(&self.base_url, &self.x_api_key, name, &upload_id)
.await?;
Ok(utils::parse_response_body(response).await?)
}
pub async fn put_file(
&self,
name: &str,
data: Vec<u8>,
content_type: Option<&str>,
) -> Result<PutFileResult> {
if data.len() <= constants::MAX_DATA_CHUNK_SIZE {
let response = requests::put_file_request(
&self.base_url,
&self.x_api_key,
name,
data,
content_type,
)
.await?;
return Ok(PutFileResult::SinglePut(
utils::parse_response_body(response).await?,
));
}
Ok(PutFileResult::ChunkedUpload(
self.perform_chunked_upload(name, data).await?,
))
}
pub async fn get_file_as_buffer(&self, name: &str) -> Result<Option<bytes::Bytes>> {
let response_result =
requests::get_file_request(&self.base_url, &self.x_api_key, name).await;
if let Err(ref error) = response_result {
if error.is_not_found() {
return Ok(None);
}
}
let response = response_result?;
let bytes = response.bytes().await?;
Ok(Some(bytes))
}
pub async fn get_file_as_u8_vec(&self, name: &str) -> Result<Option<Vec<u8>>> {
let bytes = self.get_file_as_buffer(name).await?;
if bytes.is_none() {
return Ok(None);
}
let bytes = bytes.unwrap();
Ok(Some(bytes.to_vec()))
}
pub async fn list_files(
&self,
limit: Option<u32>,
prefix: Option<&str>,
last_name: Option<&str>,
) -> Result<models::ListFiles> {
let response =
requests::list_files_request(&self.base_url, &self.x_api_key, limit, prefix, last_name)
.await?;
return Ok(utils::parse_response_body(response).await?);
}
pub async fn delete_files(&self, names: &[String]) -> Result<models::DeleteFiles> {
let response =
requests::delete_files_request(&self.base_url, &self.x_api_key, names).await?;
return Ok(utils::parse_response_body(response).await?);
}
}
#[derive(Debug, Clone)]
pub enum PutFileResult {
SinglePut(models::PutFile),
ChunkedUpload(models::EndChunkedUpload),
}