1use std::{
2 error,
3 fmt::{self, Display},
4 fs::File,
5 io::{BufReader, Read},
6 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
7 str::FromStr,
8};
9
10use prost::{DecodeError, Message};
11use rusty_ulid::Ulid;
12
13use crate::{
14 proto::{
15 command::{
16 ip_address, request::RequestType, InitialState, IpAddress, LoadBalancingAlgorithms,
17 PathRuleKind, Request, RequestHttpFrontend, RulePosition, SocketAddress, Uint128,
18 WorkerRequest,
19 },
20 display::format_request_type,
21 },
22 response::HttpFrontend,
23};
24
25#[derive(thiserror::Error, Debug)]
26pub enum RequestError {
27 #[error("invalid value {value} for field '{name}'")]
28 InvalidValue { name: String, value: i32 },
29 #[error("Could not read requests from file: {0}")]
30 ReadFile(std::io::Error),
31 #[error("Could not decode requests: {0}")]
32 Decode(DecodeError),
33}
34
35impl Request {
36 pub fn get_destinations(&self) -> ProxyDestinations {
38 let mut proxy_destination = ProxyDestinations {
39 to_http_proxy: false,
40 to_https_proxy: false,
41 to_tcp_proxy: false,
42 };
43 let request_type = match &self.request_type {
44 Some(t) => t,
45 None => return proxy_destination,
46 };
47
48 match request_type {
49 RequestType::AddHttpFrontend(_) | RequestType::RemoveHttpFrontend(_) => {
50 proxy_destination.to_http_proxy = true
51 }
52
53 RequestType::AddHttpsFrontend(_)
54 | RequestType::RemoveHttpsFrontend(_)
55 | RequestType::AddCertificate(_)
56 | RequestType::QueryCertificatesFromWorkers(_)
57 | RequestType::ReplaceCertificate(_)
58 | RequestType::RemoveCertificate(_) => proxy_destination.to_https_proxy = true,
59
60 RequestType::AddTcpFrontend(_) | RequestType::RemoveTcpFrontend(_) => {
61 proxy_destination.to_tcp_proxy = true
62 }
63
64 RequestType::AddCluster(_)
65 | RequestType::AddBackend(_)
66 | RequestType::RemoveCluster(_)
67 | RequestType::RemoveBackend(_)
68 | RequestType::SoftStop(_)
69 | RequestType::HardStop(_)
70 | RequestType::Status(_) => {
71 proxy_destination.to_http_proxy = true;
72 proxy_destination.to_https_proxy = true;
73 proxy_destination.to_tcp_proxy = true;
74 }
75
76 RequestType::ConfigureMetrics(_)
78 | RequestType::QueryMetrics(_)
79 | RequestType::Logging(_)
80 | RequestType::QueryClustersHashes(_)
81 | RequestType::QueryClusterById(_)
82 | RequestType::QueryClustersByDomain(_) => {}
83
84 RequestType::AddHttpsListener(_)
87 | RequestType::AddHttpListener(_)
88 | RequestType::AddTcpListener(_)
89 | RequestType::RemoveListener(_)
90 | RequestType::ActivateListener(_)
91 | RequestType::DeactivateListener(_)
92 | RequestType::ReturnListenSockets(_) => {}
93
94 RequestType::SaveState(_)
96 | RequestType::CountRequests(_)
97 | RequestType::QueryCertificatesFromTheState(_)
98 | RequestType::LoadState(_)
99 | RequestType::ListWorkers(_)
100 | RequestType::ListFrontends(_)
101 | RequestType::ListListeners(_)
102 | RequestType::LaunchWorker(_)
103 | RequestType::UpgradeMain(_)
104 | RequestType::UpgradeWorker(_)
105 | RequestType::SubscribeEvents(_)
106 | RequestType::ReloadConfiguration(_) => {}
107 }
108 proxy_destination
109 }
110
111 pub fn is_a_stop(&self) -> bool {
113 matches!(
114 self.request_type,
115 Some(RequestType::SoftStop(_)) | Some(RequestType::HardStop(_))
116 )
117 }
118
119 pub fn short_name(&self) -> &str {
120 match &self.request_type {
121 Some(request_type) => format_request_type(request_type),
122 None => "Unallowed",
123 }
124 }
125}
126
127impl WorkerRequest {
128 pub fn new(id: String, content: Request) -> Self {
129 Self { id, content }
130 }
131}
132
133impl fmt::Display for WorkerRequest {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 write!(f, "{}-{:?}", self.id, self.content)
136 }
137}
138
139pub fn read_initial_state_from_file(file: &mut File) -> Result<InitialState, RequestError> {
140 let mut buf_reader = BufReader::new(file);
141 read_initial_state(&mut buf_reader)
142}
143
144pub fn read_initial_state<R: Read>(reader: &mut R) -> Result<InitialState, RequestError> {
145 let mut buffer = Vec::new();
146 reader
147 .read_to_end(&mut buffer)
148 .map_err(RequestError::ReadFile)?;
149
150 InitialState::decode(&buffer[..]).map_err(RequestError::Decode)
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Hash)]
154pub struct ProxyDestinations {
155 pub to_http_proxy: bool,
156 pub to_https_proxy: bool,
157 pub to_tcp_proxy: bool,
158}
159
160impl RequestHttpFrontend {
161 pub fn to_frontend(self) -> Result<HttpFrontend, RequestError> {
163 Ok(HttpFrontend {
164 address: self.address.into(),
165 cluster_id: self.cluster_id,
166 hostname: self.hostname,
167 path: self.path,
168 method: self.method,
169 position: RulePosition::try_from(self.position).map_err(|_| {
170 RequestError::InvalidValue {
171 name: "position".to_string(),
172 value: self.position,
173 }
174 })?,
175 tags: Some(self.tags),
176 })
177 }
178}
179
180impl Display for RequestHttpFrontend {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 let s = match &PathRuleKind::try_from(self.path.kind) {
184 Ok(PathRuleKind::Prefix) => {
185 format!("{};{};P{}", self.address, self.hostname, self.path.value)
186 }
187 Ok(PathRuleKind::Regex) => {
188 format!("{};{};R{}", self.address, self.hostname, self.path.value)
189 }
190 Ok(PathRuleKind::Equals) => {
191 format!("{};{};={}", self.address, self.hostname, self.path.value)
192 }
193 Err(e) => format!("Wrong variant of PathRuleKind: {e}"),
194 };
195
196 match &self.method {
197 Some(method) => write!(f, "{s};{method}"),
198 None => write!(f, "{s}"),
199 }
200 }
201}
202
203#[derive(Debug)]
204pub struct ParseErrorLoadBalancing;
205
206impl fmt::Display for ParseErrorLoadBalancing {
207 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 write!(f, "Cannot find the load balancing policy asked")
209 }
210}
211
212impl error::Error for ParseErrorLoadBalancing {
213 fn description(&self) -> &str {
214 "Cannot find the load balancing policy asked"
215 }
216
217 fn cause(&self) -> Option<&dyn error::Error> {
218 None
219 }
220}
221
222impl FromStr for LoadBalancingAlgorithms {
223 type Err = ParseErrorLoadBalancing;
224
225 fn from_str(s: &str) -> Result<Self, Self::Err> {
226 match s.to_lowercase().as_str() {
227 "round_robin" => Ok(LoadBalancingAlgorithms::RoundRobin),
228 "random" => Ok(LoadBalancingAlgorithms::Random),
229 "power_of_two" => Ok(LoadBalancingAlgorithms::PowerOfTwo),
230 "least_loaded" => Ok(LoadBalancingAlgorithms::LeastLoaded),
231 _ => Err(ParseErrorLoadBalancing {}),
232 }
233 }
234}
235
236impl SocketAddress {
237 pub fn new_v4(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self {
238 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(a, b, c, d)), port).into()
239 }
240}
241
242impl From<SocketAddr> for SocketAddress {
243 fn from(socket_addr: SocketAddr) -> SocketAddress {
244 let ip_inner = match socket_addr {
245 SocketAddr::V4(ip_v4_addr) => ip_address::Inner::V4(u32::from(*ip_v4_addr.ip())),
246 SocketAddr::V6(ip_v6_addr) => {
247 ip_address::Inner::V6(Uint128::from(u128::from(*ip_v6_addr.ip())))
248 }
249 };
250
251 SocketAddress {
252 port: socket_addr.port() as u32,
253 ip: IpAddress {
254 inner: Some(ip_inner),
255 },
256 }
257 }
258}
259
260impl From<SocketAddress> for SocketAddr {
261 fn from(socket_address: SocketAddress) -> Self {
262 let port = socket_address.port as u16;
263
264 let ip = match socket_address.ip.inner {
265 Some(inner) => match inner {
266 ip_address::Inner::V4(v4_value) => IpAddr::V4(Ipv4Addr::from(v4_value)),
267 ip_address::Inner::V6(v6_value) => IpAddr::V6(Ipv6Addr::from(u128::from(v6_value))),
268 },
269 None => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), };
271
272 SocketAddr::new(ip, port)
273 }
274}
275
276impl From<Uint128> for u128 {
277 fn from(value: Uint128) -> Self {
278 value.low as u128 | ((value.high as u128) << 64)
279 }
280}
281
282impl From<u128> for Uint128 {
283 fn from(value: u128) -> Self {
284 let low = value as u64;
285 let high = (value >> 64) as u64;
286 Uint128 { low, high }
287 }
288}
289
290impl From<i128> for Uint128 {
291 fn from(value: i128) -> Self {
292 Uint128::from(value as u128)
293 }
294}
295
296impl From<Ulid> for Uint128 {
297 fn from(value: Ulid) -> Self {
298 let (low, high) = value.into();
299 Uint128 { low, high }
300 }
301}
302
303impl From<Uint128> for Ulid {
304 fn from(value: Uint128) -> Self {
305 let Uint128 { low, high } = value;
306 Ulid::from((low, high))
307 }
308}