pixeldrain/
client.rs

1use crate::Error;
2use crate::FileInfo;
3use crate::FileUpload;
4use crate::ListUserFilesResponse;
5use crate::UploadFileResponse;
6use base64::prelude::*;
7use reqwest::header::AUTHORIZATION;
8use std::sync::Arc;
9
10#[derive(Debug)]
11struct ClientState {
12    token: Option<String>,
13}
14
15/// The client
16#[derive(Debug, Clone)]
17pub struct Client {
18    client: reqwest::Client,
19    state: Arc<std::sync::Mutex<ClientState>>,
20}
21
22impl Client {
23    /// Make a new client.
24    pub fn new() -> Self {
25        Self {
26            client: reqwest::Client::new(),
27            state: Arc::new(std::sync::Mutex::new(ClientState { token: None })),
28        }
29    }
30
31    /// Set the token.
32    pub fn set_token(&self, token: &str) {
33        let token = format!(":{token}");
34        let mut encoded_token =
35            String::with_capacity(base64::encoded_len(token.len(), true).unwrap_or(0));
36        BASE64_STANDARD.encode_string(token, &mut encoded_token);
37
38        self.state.lock().expect("state poisoned").token = Some(encoded_token);
39    }
40
41    /// Try to get the token.
42    pub fn try_get_token(&self) -> Option<String> {
43        self.state.lock().expect("state poisoned").token.clone()
44    }
45
46    /// Get the token.
47    pub fn get_token(&self) -> Result<String, Error> {
48        self.try_get_token().ok_or(Error::MissingToken)
49    }
50
51    /// List user files.
52    ///
53    /// This function requires a token.
54    pub async fn list_user_files(&self) -> Result<ListUserFilesResponse, Error> {
55        let token = self.get_token()?;
56        let response = self
57            .client
58            .get("https://pixeldrain.com/api/user/files")
59            .header(AUTHORIZATION, format!("Basic {token}"))
60            .send()
61            .await?
62            .error_for_status()?;
63
64        let value: ListUserFilesResponse = response.json().await?;
65
66        Ok(value)
67    }
68
69    /// Upload a file.
70    ///
71    /// This function requires a token.
72    pub async fn upload_file(&self, file: FileUpload) -> Result<UploadFileResponse, Error> {
73        let token = self.get_token()?;
74
75        let response = self
76            .client
77            .put(format!(
78                "https://pixeldrain.com/api/file/{}",
79                file.file_name
80            ))
81            .header(AUTHORIZATION, format!("Basic {token}"))
82            .body(file.body)
83            .send()
84            .await?
85            .error_for_status()?;
86
87        let value: UploadFileResponse = response.json().await?;
88
89        Ok(value)
90    }
91
92    /// Get info about a file.
93    ///
94    /// This function does NOT require a token.
95    pub async fn get_file_info(&self, id: &str) -> Result<FileInfo, Error> {
96        let token = self.try_get_token();
97
98        let mut request = self
99            .client
100            .get(format!("https://pixeldrain.com/api/file/{id}/info"));
101        if let Some(token) = token {
102            request = request.header(AUTHORIZATION, format!("Basic {token}"));
103        }
104        let response = request.send().await?.error_for_status()?;
105        let value: FileInfo = response.json().await?;
106
107        Ok(value)
108    }
109
110    /// Download a file.
111    ///
112    /// This function does NOT require a token.
113    pub async fn download_file(&self, id: &str) -> Result<reqwest::Response, Error> {
114        let token = self.try_get_token();
115
116        let mut request = self
117            .client
118            .get(format!("https://pixeldrain.com/api/file/{id}"));
119        if let Some(token) = token {
120            request = request.header(AUTHORIZATION, format!("Basic {token}"));
121        }
122        let response = request.send().await?.error_for_status()?;
123
124        Ok(response)
125    }
126}
127
128impl Default for Client {
129    fn default() -> Self {
130        Self::new()
131    }
132}