filesvc_rs/
http.rs

1use std::{fs, path::Path, time::Duration};
2
3use derive_builder::Builder;
4use reqwest::{Body, Method, StatusCode};
5use thiserror::Error;
6
7impl<'a> super::Client<'a> {
8    pub async fn upload_web_file<P: AsRef<Path>>(
9        &self,
10        path: P,
11        upload: Upload,
12    ) -> Result<(String, String), UploadError> {
13        let bytes = fs::read(path)?;
14        self.upload_web(bytes, upload).await
15    }
16
17    pub async fn upload_web<'b, B: Into<Body>>(
18        &self,
19        body: B,
20        upload: Upload,
21    ) -> Result<(String, String), UploadError> {
22        let mut request = self
23            .http
24            .request(
25                Method::PUT,
26                format!("{}{}/", upload.protocol.to_string(), self.base_uri),
27            )
28            .body(body);
29
30        if let Some(filename) = upload.filename {
31            request = request.query(&[("filename", filename)]);
32        }
33
34        if let Some(randomizefn) = upload.randomizefn {
35            request = request.query(&[("randomizefn", randomizefn as i32)]);
36        }
37
38        if let Some(expire) = upload.expire {
39            request = request.query(&[("expire", expire.as_secs() / 60)]);
40        }
41
42        if let Some(autodestroy) = upload.autodestroy {
43            request = request.query(&[("autodestroy", autodestroy as i32)]);
44        }
45
46        if let Some(shorturl) = upload.shorturl {
47            request = request.query(&[("shorturl", shorturl as i32)]);
48        }
49
50        let response = request.send().await?;
51
52        let content = match response.status() {
53            StatusCode::OK => response.text().await?,
54            StatusCode::PAYLOAD_TOO_LARGE => return Err(UploadError::PayloadTooLarge),
55            status => return Err(UploadError::UnknownStatusCode(status)),
56        };
57
58        if !content.contains("[Admin]") || !content.contains("[Download]") {
59            return Err(UploadError::MalformedResponse(content));
60        }
61
62        let mut lines = content.lines().skip(1);
63
64        let admin_url = lines
65            .next()
66            .ok_or(UploadError::MalformedResponse(content.to_owned()))?
67            .strip_suffix(" [Admin]")
68            .ok_or(UploadError::MalformedResponse(content.to_owned()))?
69            .to_string();
70        let download_url = lines
71            .next()
72            .ok_or(UploadError::MalformedResponse(content.to_owned()))?
73            .strip_suffix(" [Download]")
74            .ok_or(UploadError::MalformedResponse(content.to_owned()))?
75            .to_string();
76
77        Ok((admin_url, download_url))
78    }
79}
80
81#[derive(Debug, Error)]
82pub enum UploadError {
83    #[error("The payload you are trying to upload is too large")]
84    PayloadTooLarge,
85    #[error("The server returned an unknown status code {0}")]
86    UnknownStatusCode(StatusCode),
87    #[error("The server returned a malformed response {0}")]
88    MalformedResponse(String),
89    #[error(transparent)]
90    Io(#[from] std::io::Error),
91    #[error(transparent)]
92    Http(#[from] reqwest::Error),
93}
94
95#[derive(Default, Debug, Clone, Builder)]
96#[builder(setter(into), default)]
97pub struct Upload {
98    protocol: UploadProtocol,
99    filename: Option<String>,
100    randomizefn: Option<bool>,
101    expire: Option<Duration>,
102    autodestroy: Option<bool>,
103    shorturl: Option<bool>,
104}
105
106impl Upload {
107    pub fn builder() -> UploadBuilder {
108        UploadBuilder::default()
109    }
110}
111
112#[derive(Default, Debug, Clone)]
113pub enum UploadMethod {
114    #[default]
115    Put,
116    Post,
117}
118
119#[derive(Default, Debug, Clone)]
120pub enum UploadProtocol {
121    #[default]
122    Https,
123    Http,
124}
125
126impl ToString for UploadProtocol {
127    fn to_string(&self) -> String {
128        match self {
129            UploadProtocol::Https => "https://".to_string(),
130            UploadProtocol::Http => "http://".to_string(),
131        }
132    }
133}