🏗️ Elegant & Highly Performant Async Gemini Server Framework for the Modern Age
async
framework
gemini-protocol
protocol
gemini
rust
1//! Content and response handlers
2
3#[cfg(feature = "response-macros")]
4mod macros;
5
6macro_rules! response {
7 ($name:ident, $status:expr) => {
8 pub fn $name<S>(content: S) -> Self
9 where S: Into<String> + AsRef<str> {
10 Self::new($status, content.into())
11 }
12 };
13}
14
15/// The content and response type a handler should reply with.
16#[derive(Clone)]
17pub struct Response {
18 pub status: i32,
19 pub mime: Option<String>,
20 pub content: String,
21 pub character_set: Option<String>,
22 pub languages: Option<Vec<String>>,
23}
24
25impl Response {
26 response!(input, 10);
27
28 response!(sensitive_input, 11);
29
30 response!(temporary_redirect, 30);
31
32 response!(permanent_redirect, 31);
33
34 response!(temporary_failure, 40);
35
36 response!(server_unavailable, 41);
37
38 response!(cgi_error, 42);
39
40 response!(proxy_error, 43);
41
42 response!(slow_down, 44);
43
44 response!(permanent_failure, 50);
45
46 response!(not_found, 51);
47
48 response!(gone, 52);
49
50 response!(proxy_refused, 53);
51
52 response!(bad_request, 59);
53
54 response!(client_certificate_required, 60);
55
56 response!(certificate_not_authorised, 61);
57
58 response!(certificate_not_valid, 62);
59
60 #[allow(clippy::needless_pass_by_value)]
61 pub fn success(content: impl ToString) -> Self {
62 let mut response = Self::new(20, content.to_string());
63
64 response
65 .with_mime("text/gemini")
66 .with_languages(["en"])
67 .with_character_set("utf-8");
68
69 response
70 }
71
72 #[must_use]
73 pub fn binary_success(
74 content: impl AsRef<[u8]>,
75 mime: impl Into<String> + AsRef<str>,
76 ) -> Self {
77 let mut response = Self::new(21, String::from_utf8_lossy(content.as_ref()));
78
79 response.with_mime(mime);
80
81 response
82 }
83
84 #[cfg(feature = "auto-deduce-mime")]
85 #[must_use]
86 pub fn binary_success_auto(content: &[u8]) -> Self {
87 let mut response = Self::new(22, String::from_utf8_lossy(content));
88
89 response.with_mime(tree_magic_mini::from_u8(content));
90
91 response
92 }
93
94 #[must_use]
95 pub fn new(status: i32, content: impl Into<String> + AsRef<str>) -> Self {
96 Self {
97 status,
98 mime: None,
99 content: content.into(),
100 character_set: None,
101 languages: None,
102 }
103 }
104
105 pub fn with_mime(
106 &mut self,
107 mime: impl Into<String> + AsRef<str>,
108 ) -> &mut Self {
109 self.mime = Some(mime.into());
110
111 self
112 }
113
114 pub fn with_character_set(
115 &mut self,
116 character_set: impl Into<String> + AsRef<str>,
117 ) -> &mut Self {
118 self.character_set = Some(character_set.into());
119
120 self
121 }
122
123 pub fn with_languages<S>(&mut self, languages: impl AsRef<[S]>) -> &mut Self
124 where S: Into<String> + AsRef<str> {
125 self.languages = Some(
126 languages
127 .as_ref()
128 .iter()
129 .map(|s| s.as_ref().to_string())
130 .collect::<Vec<String>>(),
131 );
132
133 self
134 }
135}
136
137impl std::future::IntoFuture for Response {
138 type IntoFuture = std::future::Ready<Self::Output>;
139 type Output = Self;
140
141 fn into_future(self) -> Self::IntoFuture { std::future::ready(self) }
142}