use crate::{error::Result, resources::file::File};
use reqwest::{
multipart::{Form, Part},
Client,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Default, Serialize)]
pub struct UploadRequest {
pub name: String,
pub size: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_folder_id: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_folder_path: Option<String>,
}
#[derive(Debug, Deserialize)]
struct UploadIntent {
upload_url: String,
upload_params: HashMap<String, String>,
}
pub(crate) async fn execute_upload(
client: &Client,
upload_url: &str,
upload_params: HashMap<String, String>,
filename: String,
content_type: String,
data: Vec<u8>,
) -> Result<File> {
let mut form = Form::new();
for (key, value) in upload_params {
form = form.text(key, value);
}
let file_part = Part::bytes(data.clone()).file_name(filename.clone());
let file_part = file_part
.mime_str(&content_type)
.unwrap_or_else(|_| Part::bytes(data).file_name(filename));
form = form.part("file", file_part);
let resp = client.post(upload_url).multipart(form).send().await?;
let body = resp.text().await?;
let json_str = body.strip_prefix("while(1);").unwrap_or(&body);
let file: File = serde_json::from_str(json_str)?;
Ok(file)
}
pub(crate) async fn initiate_and_upload(
requester: &crate::http::Requester,
endpoint: &str,
request: UploadRequest,
data: Vec<u8>,
) -> Result<File> {
let params = crate::params::flatten_params(&serde_json::to_value(&request).unwrap());
let intent: UploadIntent = requester.post(endpoint, ¶ms).await?;
let content_type = request
.content_type
.unwrap_or_else(|| "application/octet-stream".to_string());
execute_upload(
&requester.client,
&intent.upload_url,
intent.upload_params,
request.name,
content_type,
data,
)
.await
}