quartz_cli/
snippet.rs

1use std::ops::Deref;
2
3use crate::{Endpoint, QuartzResult};
4use hyper::{Body, Request, Response};
5
6enum CurlOption {
7    Location,
8    Request,
9    Header,
10    Data,
11}
12
13#[derive(clap::Args, Debug)]
14pub struct Curl {
15    /// Use long form cURL options (--header instead of -H)
16    #[arg(long)]
17    long: bool,
18
19    /// Split output across multiple lines
20    #[arg(long)]
21    multiline: bool,
22}
23
24impl Curl {
25    pub fn print(&self, endpoint: &mut Endpoint) -> QuartzResult {
26        let separator = if self.multiline { " \\\n\t" } else { " " };
27
28        print!(
29            "curl {} '{}'",
30            self.option_string(CurlOption::Location),
31            endpoint.full_url().unwrap()
32        );
33        print!(
34            " {} {}",
35            self.option_string(CurlOption::Request),
36            endpoint.method
37        );
38
39        for (key, value) in endpoint.headers.iter() {
40            print!(
41                "{}{} '{}: {}'",
42                separator,
43                self.option_string(CurlOption::Header),
44                key,
45                value
46            );
47        }
48
49        if let Some(body) = endpoint.body() {
50            let mut body = body.to_owned();
51            print!("{}{} '", separator, self.option_string(CurlOption::Data));
52
53            if body.ends_with('\n') {
54                body.truncate(body.len() - 1);
55            }
56
57            print!("{body}");
58            println!("'");
59        } else {
60            println!();
61        }
62
63        Ok(())
64    }
65
66    fn option_string(&self, option: CurlOption) -> String {
67        let result = match option {
68            CurlOption::Location => {
69                if self.long {
70                    "--location"
71                } else {
72                    "-L"
73                }
74            }
75            CurlOption::Request => {
76                if self.long {
77                    "--request"
78                } else {
79                    "-X"
80                }
81            }
82            CurlOption::Header => {
83                if self.long {
84                    "--header"
85                } else {
86                    "-H"
87                }
88            }
89            CurlOption::Data => {
90                if self.long {
91                    "--data"
92                } else {
93                    "-d"
94                }
95            }
96        };
97
98        result.to_string()
99    }
100}
101
102pub struct Http(String);
103
104impl Deref for Http {
105    type Target = String;
106
107    fn deref(&self) -> &Self::Target {
108        &self.0
109    }
110}
111
112impl From<&Response<Body>> for Http {
113    fn from(value: &Response<Body>) -> Self {
114        let mut output = String::new();
115
116        output.push_str(&format!("< {:?}", value.version()));
117        output.push_str(&format!(" {:?}", value.status()));
118        output.push('\n');
119
120        for (k, v) in value.headers().iter() {
121            output.push_str(&format!(
122                "< {}: {}\n",
123                k.as_str(),
124                v.to_str().unwrap_or_default()
125            ))
126        }
127
128        output.push('<');
129
130        Self(output)
131    }
132}
133
134impl From<&Request<Body>> for Http {
135    fn from(value: &Request<Body>) -> Self {
136        let mut output = String::new();
137
138        output.push_str(&format!(
139            "> {} {} {:?}\n",
140            value.method(),
141            value.uri().path_and_query().unwrap().as_str(),
142            value.version()
143        ));
144        output.push_str(&format!("> Host: {}\n", value.uri().host().unwrap()));
145
146        for (k, v) in value.headers().iter() {
147            output.push_str(&format!(
148                "> {}: {}\n",
149                k.as_str(),
150                v.to_str().unwrap_or_default()
151            ))
152        }
153
154        output.push('>');
155
156        Self(output)
157    }
158}
159
160impl Http {
161    pub fn print(endpoint: &mut Endpoint) -> QuartzResult {
162        let url = endpoint.full_url()?;
163        let path = url.path_and_query().unwrap();
164
165        println!("{} {} HTTP/1.1", endpoint.method, path.as_str());
166        println!("Host: {}", url.host().unwrap());
167        print!("{}", endpoint.headers);
168
169        if let Some(body) = endpoint.body() {
170            println!();
171            print!("{body}");
172        }
173
174        Ok(())
175    }
176}