1use crate::{error::Result, resources::file::File};
6use reqwest::{
7 multipart::{Form, Part},
8 Client,
9};
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13#[derive(Debug, Default, Serialize)]
14pub struct UploadRequest {
15 pub name: String,
16 pub size: u64,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub content_type: Option<String>,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub parent_folder_id: Option<u64>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub parent_folder_path: Option<String>,
23}
24
25#[derive(Debug, Deserialize)]
26struct UploadIntent {
27 upload_url: String,
28 upload_params: HashMap<String, String>,
29}
30
31pub(crate) async fn execute_upload(
34 client: &Client,
35 upload_url: &str,
36 upload_params: HashMap<String, String>,
37 filename: String,
38 content_type: String,
39 data: Vec<u8>,
40) -> Result<File> {
41 let mut form = Form::new();
43 for (key, value) in upload_params {
44 form = form.text(key, value);
45 }
46
47 let file_part = Part::bytes(data.clone()).file_name(filename.clone());
49 let file_part = file_part
50 .mime_str(&content_type)
51 .unwrap_or_else(|_| Part::bytes(data).file_name(filename));
52
53 form = form.part("file", file_part);
54
55 let resp = client.post(upload_url).multipart(form).send().await?;
56
57 let body = resp.text().await?;
58
59 let json_str = body.strip_prefix("while(1);").unwrap_or(&body);
61
62 let file: File = serde_json::from_str(json_str)?;
63 Ok(file)
64}
65
66pub(crate) async fn initiate_and_upload(
68 requester: &crate::http::Requester,
69 endpoint: &str,
70 request: UploadRequest,
71 data: Vec<u8>,
72) -> Result<File> {
73 let params = crate::params::flatten_params(&serde_json::to_value(&request).unwrap());
75
76 let intent: UploadIntent = requester.post(endpoint, ¶ms).await?;
77
78 let content_type = request
80 .content_type
81 .unwrap_or_else(|| "application/octet-stream".to_string());
82
83 execute_upload(
84 &requester.client,
85 &intent.upload_url,
86 intent.upload_params,
87 request.name,
88 content_type,
89 data,
90 )
91 .await
92}