pickcat_api_collection/
media.rs1use crate::dto::media::{FileListDTO, UploadedFileDTO};
6use crate::{Error, PickcatAccound};
7
8pub trait MediaBehavior {
14 fn upload_file(
19 &self,
20 idempotency_key: &str,
21 ownership: &str,
22 file_name: &str,
23 bytes: Vec<u8>,
24 ) -> impl std::future::Future<Output = Result<UploadedFileDTO, Error>> + Send;
25
26 fn list_files(
28 &self,
29 scope: Option<&str>,
30 state: Option<&str>,
31 limit: Option<u32>,
32 cursor: Option<&str>,
33 ) -> impl std::future::Future<Output = Result<FileListDTO, Error>> + Send;
34
35 fn get_file(
37 &self,
38 file_id: &str,
39 ) -> impl std::future::Future<Output = Result<Vec<u8>, Error>> + Send;
40
41 fn get_avatar(
43 &self,
44 id: &str,
45 version: Option<&str>,
46 ) -> impl std::future::Future<Output = Result<Vec<u8>, Error>> + Send;
47
48 fn get_emoji_image(
50 &self,
51 emoji_name: &str,
52 emoji_read: Option<&str>,
53 ) -> impl std::future::Future<Output = Result<Vec<u8>, Error>> + Send;
54}
55
56impl MediaBehavior for PickcatAccound {
57 async fn upload_file(
58 &self,
59 idempotency_key: &str,
60 ownership: &str,
61 file_name: &str,
62 bytes: Vec<u8>,
63 ) -> Result<UploadedFileDTO, Error> {
64 let part = reqwest::multipart::Part::bytes(bytes).file_name(file_name.to_string());
65 let form = reqwest::multipart::Form::new()
66 .text("ownership", ownership.to_string())
67 .part("file", part);
68
69 Ok(self
70 .client
71 .post(format!("{}/api/v1/files", self.base_url))
72 .header("Idempotency-Key", idempotency_key)
73 .header("origin", self.base_url.clone())
74 .multipart(form)
75 .send()
76 .await?
77 .json::<UploadedFileDTO>()
78 .await?)
79 }
80
81 async fn list_files(
82 &self,
83 scope: Option<&str>,
84 state: Option<&str>,
85 limit: Option<u32>,
86 cursor: Option<&str>,
87 ) -> Result<FileListDTO, Error> {
88 let mut params: Vec<(&str, String)> = Vec::new();
89 if let Some(scope) = scope {
90 params.push(("scope", scope.to_string()));
91 }
92 if let Some(state) = state {
93 params.push(("state", state.to_string()));
94 }
95 if let Some(limit) = limit {
96 params.push(("limit", limit.to_string()));
97 }
98 if let Some(cursor) = cursor {
99 params.push(("cursor", cursor.to_string()));
100 }
101
102 let mut request = self.client.get(format!("{}/api/v1/files", self.base_url));
103 if !params.is_empty() {
104 request = request.query(¶ms);
105 }
106 Ok(request.send().await?.json::<FileListDTO>().await?)
107 }
108
109 async fn get_file(&self, file_id: &str) -> Result<Vec<u8>, Error> {
110 Ok(self
111 .client
112 .get(format!("{}/api/v1/files/{}", self.base_url, file_id))
113 .send()
114 .await?
115 .error_for_status()?
116 .bytes()
117 .await?
118 .to_vec())
119 }
120
121 async fn get_avatar(&self, id: &str, version: Option<&str>) -> Result<Vec<u8>, Error> {
122 let mut request = self
123 .client
124 .get(format!("{}/api/v1/avatars/{}", self.base_url, id));
125 if let Some(version) = version {
126 request = request.query(&[("v", version)]);
127 }
128 Ok(request
129 .send()
130 .await?
131 .error_for_status()?
132 .bytes()
133 .await?
134 .to_vec())
135 }
136
137 async fn get_emoji_image(
138 &self,
139 emoji_name: &str,
140 emoji_read: Option<&str>,
141 ) -> Result<Vec<u8>, Error> {
142 let mut request = self.client.get(format!(
143 "{}/api/v1/emojis/{}/image",
144 self.base_url, emoji_name
145 ));
146 if let Some(emoji_read) = emoji_read {
147 request = request.query(&[("emoji-read", emoji_read)]);
148 }
149 Ok(request
150 .send()
151 .await?
152 .error_for_status()?
153 .bytes()
154 .await?
155 .to_vec())
156 }
157}