gitignore_template_generator/http_client/
impls.rs

1use std::{collections::HashMap, time::Duration};
2
3use ureq::Agent;
4
5use crate::{
6    constant,
7    core::{ExitKind, ProgramExit},
8    http_client::api::HttpClient,
9};
10
11/// Http client implementation relying on [`ureq`].
12#[derive(Default)]
13pub struct UreqHttpClient {
14    /// The base url of the HTTP server to reach.
15    ///
16    /// Used as base url when calling [`UreqHttpClient::get`] method.
17    pub server_url: String,
18
19    /// The timeout for the entire HTTP call.
20    pub global_timeout: Option<Duration>,
21}
22
23/// Http client implementation to mock a response.
24pub struct MockHttpClient {
25    /// The mocked response to be returned when calling [`MockHttpClient::get`]
26    /// method.
27    pub response: Result<String, ProgramExit>,
28}
29
30/// Http client implementation to mock a response.
31pub struct MockEndpointHttpClient<'a> {
32    /// The mocked response to be returned when calling [`MockHttpClient::get`]
33    /// method.
34    pub response: HashMap<&'a str, Result<String, ProgramExit>>,
35}
36
37impl HttpClient for UreqHttpClient {
38    /// Make a GET HTTP call using a [`ureq`] client.
39    ///
40    /// The server base url (i.e. https://localhost:8080) should be provided
41    /// as part of [`UreqHttpClient::server_url] field.
42    ///
43    /// See [`HttpClient::get`] for more infos.
44    fn get(&self, url: &str) -> Result<String, ProgramExit> {
45        let full_url = format!("{}{url}", self.server_url);
46        let agent: Agent = Agent::config_builder()
47            .timeout_global(Some(self.global_timeout.unwrap_or(
48                Duration::from_secs(
49                    constant::template_manager::TIMEOUT.parse().expect(
50                        constant::error_messages::FAILED_U64_CONVERSION,
51                    ),
52                ),
53            )))
54            .build()
55            .into();
56
57        let result = agent.get(full_url).call();
58
59        match result {
60            Ok(mut response) => match response.body_mut().read_to_string() {
61                Ok(body) => Ok(body.trim().to_string()),
62                Err(error) => Err(ProgramExit {
63                    message: error.to_string(),
64                    exit_status: constant::exit_status::HTTP_CLIENT_ERROR,
65                    styled_message: None,
66                    kind: ExitKind::Error,
67                }),
68            },
69            Err(error) => Err(ProgramExit {
70                message: constant::error_messages::API_CALL_FAILURE
71                    .replace("{error}", &error.to_string()),
72                exit_status: constant::exit_status::GENERIC,
73                styled_message: None,
74                kind: ExitKind::Error,
75            }),
76        }
77    }
78}
79
80impl HttpClient for MockHttpClient {
81    /// Returns the result linked to this instance.
82    ///
83    /// The given `_url` will not be used, simply a clone of linked
84    /// result will be returned.
85    fn get(&self, _url: &str) -> Result<String, ProgramExit> {
86        self.response.clone()
87    }
88}
89
90impl HttpClient for MockEndpointHttpClient<'_> {
91    /// Returns the result linked to the given url.
92    ///
93    /// The given `url` will only be used to get proper result from linked
94    /// hashmap.
95    fn get(&self, url: &str) -> Result<String, ProgramExit> {
96        self.response[url].clone()
97    }
98}