1use async_stream::stream;
2use futures::Stream;
3use hyper::header::HeaderValue;
4use reqwest::{Client, IntoUrl, RequestBuilder, Response, Url};
5use serde::Serialize;
6
7use crate::error::errors::parsing::Parsing;
8use crate::error::errors::request::Request;
9use crate::structs::Context;
10
11use super::config::Config;
12use super::platform::Platform;
13use super::error::structs::Error;
14
15impl Platform {
16 async fn send(req: RequestBuilder) -> Result<Response, Error> {
17 req.send().await.map_err( |e| Request::fetch(e, vec!["Please check your ethernet conection"]))
18 }
19 pub async fn get<U: IntoUrl>(&self, url: U, auth: bool, config: &Config) -> Result<Response, Error> {
20 let client = Client::new();
21 let mut header = self.get_auth_header(&config.token);
22
23 if !auth {
24 match self {
25 Platform::Github => header.remove("Authorization"),
26 Platform::Gitea |
27 Platform::Codeberg |
28 Platform::Forgejo |
29 Platform::Gitlab => header.remove("authorization"),
30 };
31 }
32
33 let req = client.get(url).headers(header);
34
35 Platform::send(req).await
36 }
37 pub async fn post<T, U>(&self, url: U, header: bool, config: &Config, json: &T) -> Result<Response, Error>
38 where
39 U: IntoUrl,
40 T: Serialize + ?Sized,
41 {
42 let client = Client::new();
43
44 let mut request = client
45 .post(url)
46 .header("content-type", "application/json")
47 .json(json);
48
49 if header {
50 request = request.headers(self.get_auth_header(&config.token));
51 }
52
53 Platform::send(request).await
54 }
55
56 pub async fn delete<U: IntoUrl>(&self, url: U, config: &Config) -> Result<Response, Error> {
57 let client = Client::new();
58
59 let req = client
60 .delete(url)
61 .headers(self.get_auth_header(&config.token));
62
63 Platform::send(req).await
64 }
65
66 pub fn pagginate(&self,
67 url: String,
68 config: &Config,
69 context: Context
70 ) -> impl Stream<Item = Result<String, Error>> { stream! {
71 let client = Client::new();
72 let headers = self.get_auth_header(&config.token);
73
74 let size = 10;
75 let mut url = Url::parse(&url).map_err(|e| Parsing::url(e, &url) )?;
76
77 url.query_pairs_mut().append_pair("page", "1").append_pair("per_page", &size.to_string());
78
79 let mut next = Some(url);
80
81 while let Some(url) = next {
82
83 let response = match client.get(url).headers(headers.clone()).send().await {
84 Ok(response) => response,
85 Err(e) => {
86 yield Err(Request::fetch("Error during paggination", vec![e]));
87 return;
88 }
89 };
90
91 let response_headers = response.headers().clone();
92 let string = match self.unwrap(response, "Faild getting reponse", &config, context.clone()).await {
93 Ok(s) => s,
94 Err(e) => {
95 yield Err(e);
96 return;
97 },
98 };
99
100 yield Ok(string);
101
102 next = extract_next(response_headers.get("link"))?;
103 }
104 }}
105}
106
107fn extract_next(link_header: Option<&HeaderValue>) -> Result<Option<Url>, Error> {
108 let header = match link_header.and_then(|header| header.to_str().ok()) {
109 Some(h) => h,
110 None => return Ok(None),
111 };
112
113 let url = header.split(",")
114 .find_map(|link| -> Option<_> {
115 if link.ends_with(r#"; rel="next""#) {
116 Some(link.trim().trim_matches('<').replace(r#">; rel="next""#, ""))
117 }
118 else { None }
119 });
120
121 if url.is_none() { return Ok(None) };
122 let url = url.unwrap();
123 Url::parse(&url)
124 .map(|e| Some(e))
125 .map_err(|e| Parsing::url(e, &url) )
126}