Skip to main content

grp_core/
request.rs

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}