1use std::collections::HashMap;
2
3use quick_xml::de;
4use reqwest::Response;
5use serde::de::DeserializeOwned;
6
7use crate::model::{LoadClear, PSError, PSResult, SearchResponse, VersionCreation};
8
9use super::{
10 model::{
11 DocumentFragment, Error, EventType, FragmentCreation, Group, LoadStart, LoadUnzip,
12 SearchResultPage, Service, Thread, Upload, Uri, UriHistory,
13 },
14 PSServer,
15};
16
17impl PSServer {
18 async fn handle_http<T: DeserializeOwned>(&self, op: &str, resp: Response) -> PSResult<T> {
19 if !(200..300).contains(&resp.status().as_u16()) {
20 let err: Error = de::from_str(&resp.text().await?)?;
21 Err(PSError::ApiError {
22 id: err.id,
23 req: op.to_string(),
24 msg: err.message,
25 })
26 } else {
27 Ok(de::from_str(&resp.text().await?)?)
28 }
29 }
30
31 pub async fn get_group(&self, name: &str) -> PSResult<Group> {
33 let resp = self
34 .checked_get(Service::GetGroup { group: name }, None, None)
35 .await?;
36
37 self.handle_http("get group", resp).await
38 }
39
40 pub async fn get_uri(&self, member: &str, uri: &str) -> PSResult<Uri> {
42 let resp = self
43 .checked_get(Service::GetUri { member, uri }, None, None)
44 .await?;
45
46 self.handle_http("get uri", resp).await
47 }
48
49 pub async fn get_uri_history(&self, group: &str, uri: &str) -> PSResult<UriHistory> {
51 let resp = self
52 .checked_get(Service::GetUriHistory { group, uri }, None, None)
53 .await?;
54
55 self.handle_http("get uri history", resp).await
56 }
57
58 pub async fn get_uris_history(
61 &self,
62 group: &str,
63 events: Vec<EventType>,
64 mut params: HashMap<&str, &str>,
65 ) -> PSResult<UriHistory> {
66 let events = events
67 .into_iter()
68 .map(|e| e.into())
69 .collect::<Vec<String>>()
70 .join(",");
71 params.insert("events", &events);
72
73 let resp = self
74 .checked_get(
75 Service::GetUrisHistory { group },
76 Some(params.into_iter().collect()),
77 None,
78 )
79 .await?;
80
81 self.handle_http("get uris history", resp).await
82 }
83
84 pub async fn get_uri_fragment(
85 &self,
86 member: &str,
87 group: &str,
88 uri: &str,
89 fragment: &str,
90 params: HashMap<&str, &str>,
91 ) -> PSResult<DocumentFragment> {
92 let resp = self
93 .checked_get(
94 Service::GetUriFragment {
95 member,
96 group,
97 uri,
98 fragment,
99 },
100 Some(params.into_iter().collect()),
101 None,
102 )
103 .await?;
104
105 self.handle_http("get uri fragment", resp).await
106 }
107
108 pub async fn uri_export(
110 &self,
111 member: &str,
112 uri: &str,
113 params: Vec<(&str, &str)>,
114 ) -> PSResult<Thread> {
116 let resp = self
117 .checked_get(Service::UriExport { member, uri }, Some(params), None)
118 .await?;
119
120 self.handle_http("uri export", resp).await
121 }
122
123 pub async fn group_search(
127 &self,
128 group: &str,
129 params: HashMap<&str, &str>,
130 ) -> PSResult<Vec<SearchResultPage>> {
131 let param_vec: Vec<(&str, &str)> = params.iter().map(|t| (*t.0, *t.1)).collect();
132
133 let service = Service::GroupSearch { group };
134 let resp = self
135 .checked_get(service.clone(), Some(param_vec), None)
136 .await?;
137
138 let results = self
139 .handle_http::<SearchResponse>("group search", resp)
140 .await?
141 .results;
142
143 let mut pages = vec![];
144 if !params.contains_key("page") {
146 for page in 2..=results.total_pages {
147 let page = page.to_string();
148 let mut params = params.clone();
149
150 params.insert("page", &page);
151 let resp = self
152 .checked_get(
153 service.clone(),
154 Some(params.iter().map(|t| (*t.0, *t.1)).collect()),
155 None,
156 )
157 .await?;
158 pages.push(de::from_str(&resp.text().await?)?);
159 }
160 }
161
162 pages.insert(0, results);
163 Ok(pages)
164 }
165
166 pub async fn thread_progress(&self, thread_id: &str) -> PSResult<Thread> {
168 let resp = self
169 .checked_get(Service::ThreadProgress { id: thread_id }, None, None)
170 .await?;
171
172 self.handle_http("get thread progress", resp).await
173 }
174
175 pub async fn put_uri_fragment(
176 &self,
177 member: &str,
178 group: &str,
179 uri: &str,
180 fragment: &str,
181 content: String,
182 params: Option<Vec<(&str, &str)>>,
183 ) -> PSResult<FragmentCreation> {
184 let resp = self
185 .checked_put(
186 Service::PutUriFragment {
187 member,
188 group,
189 uri,
190 fragment,
191 },
192 params,
193 None,
194 Some(content),
195 )
196 .await?;
197
198 self.handle_http("put uri fragment", resp).await
199 }
200
201 pub async fn add_uri_fragment(
202 &self,
203 member: &str,
204 group: &str,
205 uri: &str,
206 content: &str,
207 mut params: HashMap<&str, &str>,
208 ) -> PSResult<FragmentCreation> {
209 params.insert("content", content);
210
211 let resp = self
212 .checked_post(
213 Service::AddUriFragment { member, group, uri },
214 Some(params.into_iter().collect()),
215 None,
216 Option::<&[u8]>::None,
217 )
218 .await?;
219
220 self.handle_http("add uri fragment", resp).await
221 }
222
223 pub async fn upload(
224 &self,
225 group: &str,
226 filename: &str,
227 file: Vec<u8>,
228 mut params: HashMap<&str, &str>,
229 ) -> PSResult<Upload> {
230 params.insert("group", group);
231 params.insert("filename", filename);
232
233 let resp = self
234 .checked_put(
235 Service::Upload,
236 Some(params.into_iter().collect()),
237 None,
238 Some(file),
239 )
240 .await?;
241
242 self.handle_http("upload", resp).await
243 }
244
245 pub async fn clear_loading_zone(&self, member: &str, group: &str) -> PSResult<LoadClear> {
246 let resp = self
247 .checked_post(
248 Service::ClearLoadingZone { member, group },
249 None,
250 None,
251 Option::<&[u8]>::None,
252 )
253 .await?;
254
255 self.handle_http("clear loading zone", resp).await
256 }
257
258 pub async fn unzip_loading_zone(
259 &self,
260 member: &str,
261 group: &str,
262 path: &str,
263 mut params: HashMap<&str, &str>,
264 ) -> PSResult<LoadUnzip> {
265 params.insert("path", path);
266
267 let resp = self
268 .checked_post(
269 Service::UnzipLoadingZone { member, group },
270 Some(params.into_iter().collect()),
271 None,
272 Option::<&[u8]>::None,
273 )
274 .await?;
275
276 self.handle_http("unzip loading zone content", resp).await
277 }
278
279 pub async fn start_loading(
280 &self,
281 member: &str,
282 group: &str,
283 params: HashMap<&str, &str>,
284 ) -> PSResult<LoadStart> {
285 let resp = self
286 .checked_post(
287 Service::StartLoading { member, group },
288 Some(params.into_iter().collect()),
289 None,
290 Option::<&[u8]>::None,
291 )
292 .await?;
293
294 self.handle_http("start loading the loading zone content", resp)
295 .await
296 }
297
298 pub async fn download_member_resource(&self, group: &str, filename: &str) -> PSResult<Vec<u8>> {
300 let resp = self
301 .checked_get(Service::DownloadMemberResource { group, filename }, None, None)
302 .await?;
303
304 Ok(resp.bytes().await?.to_vec())
305 }
306
307 pub async fn create_uri_version(
309 &self,
310 member: &str,
311 group: &str,
312 uri: &str,
313 name: &str,
314 mut params: HashMap<&str, &str>,
315 ) -> PSResult<VersionCreation> {
316 params.insert("name", name);
317
318 let resp = self
319 .checked_post(
320 Service::CreateUriVersion { member, group, uri },
321 Some(params.into_iter().collect()),
322 None,
323 Option::<&[u8]>::None,
324 )
325 .await?;
326
327 self.handle_http("create version", resp).await
328 }
329}