1use std::fmt::Display;
2
3use crate::constants::DEFAULT_NAMESPACE;
4
5pub use super::route_match::*;
6use serde::{Deserialize, Serialize};
7
8use super::{gateway::SgBackendProtocol, PluginInstanceId};
9
10#[derive(Debug, Serialize, Deserialize, Clone)]
14#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
15#[serde(default)]
16pub struct SgHttpRoute<P = PluginInstanceId> {
17 pub route_name: String,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub hostnames: Option<Vec<String>>,
22 #[serde(skip_serializing_if = "Vec::is_empty")]
23 pub plugins: Vec<P>,
25 #[serde(skip_serializing_if = "Vec::is_empty")]
26 pub rules: Vec<SgHttpRouteRule<P>>,
28 pub priority: i16,
30}
31
32impl<P> SgHttpRoute<P> {
33 pub fn map_plugins<F, T>(self, mut f: F) -> SgHttpRoute<T>
34 where
35 F: FnMut(P) -> T,
36 {
37 SgHttpRoute {
38 route_name: self.route_name,
39 hostnames: self.hostnames,
40 plugins: self.plugins.into_iter().map(&mut f).collect(),
41 rules: self.rules.into_iter().map(|rule| rule.map_plugins(&mut f)).collect(),
42 priority: self.priority,
43 }
44 }
45}
46
47impl<P> Default for SgHttpRoute<P> {
48 fn default() -> Self {
49 Self {
50 route_name: Default::default(),
51 hostnames: Default::default(),
52 plugins: Default::default(),
53 rules: Default::default(),
54 priority: 1,
55 }
56 }
57}
58
59#[derive(Debug, Serialize, Deserialize, Clone)]
61#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
62#[serde(default)]
63pub struct SgHttpRouteRule<P = PluginInstanceId> {
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub matches: Option<Vec<SgHttpRouteMatch>>,
67 #[serde(skip_serializing_if = "Vec::is_empty")]
68 pub plugins: Vec<P>,
70 #[serde(skip_serializing_if = "Vec::is_empty")]
71 pub backends: Vec<SgBackendRef<P>>,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub timeout_ms: Option<u32>,
76}
77
78impl<P> SgHttpRouteRule<P> {
79 pub fn map_plugins<F, T>(self, mut f: F) -> SgHttpRouteRule<T>
80 where
81 F: FnMut(P) -> T,
82 {
83 SgHttpRouteRule {
84 matches: self.matches,
85 plugins: self.plugins.into_iter().map(&mut f).collect(),
86 backends: self.backends.into_iter().map(|backend| backend.map_plugins(&mut f)).collect(),
87 timeout_ms: self.timeout_ms,
88 }
89 }
90}
91
92impl<P> Default for SgHttpRouteRule<P> {
93 fn default() -> Self {
94 Self {
95 matches: Default::default(),
96 plugins: Default::default(),
97 backends: Default::default(),
98 timeout_ms: Default::default(),
99 }
100 }
101}
102
103#[derive(Debug, Serialize, Deserialize, Clone)]
105#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
106#[serde(default)]
107pub struct SgBackendRef<P = PluginInstanceId> {
108 pub host: BackendHost,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub port: Option<u16>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub timeout_ms: Option<u32>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub protocol: Option<SgBackendProtocol>,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub downgrade_http2: Option<bool>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub weight: Option<u16>,
128 #[serde(skip_serializing_if = "Vec::is_empty")]
129 pub plugins: Vec<P>,
134}
135
136impl<P> SgBackendRef<P> {
137 pub fn map_plugins<F, T>(self, f: F) -> SgBackendRef<T>
138 where
139 F: FnMut(P) -> T,
140 {
141 SgBackendRef {
142 host: self.host,
143 port: self.port,
144 timeout_ms: self.timeout_ms,
145 protocol: self.protocol,
146 downgrade_http2: self.downgrade_http2,
147 weight: self.weight,
148 plugins: self.plugins.into_iter().map(f).collect(),
149 }
150 }
151
152 pub fn get_host(&self) -> String {
153 self.host.to_string()
154 }
155}
156
157impl<P> Default for SgBackendRef<P> {
158 fn default() -> Self {
159 Self {
160 host: Default::default(),
161 port: Default::default(),
162 timeout_ms: Default::default(),
163 downgrade_http2: Default::default(),
164 protocol: Default::default(),
165 weight: Default::default(),
166 plugins: Default::default(),
167 }
168 }
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
173pub struct K8sServiceData {
174 pub name: String,
175 #[serde(alias = "ns")]
176 pub namespace: Option<String>,
177}
178
179impl Display for K8sServiceData {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 match self.namespace {
182 Some(ref ns) => write!(f, "{}.{}", self.name, ns),
183 None => write!(f, "{}.{}", self.name, DEFAULT_NAMESPACE),
184 }
185 }
186}
187
188#[derive(Debug, Serialize, Deserialize, Clone)]
189#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
190#[serde(tag = "kind")]
191pub enum BackendHost {
192 Host { host: String },
193 K8sService(K8sServiceData),
194 File { path: String },
195}
196
197impl Display for BackendHost {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 match self {
200 Self::Host { host } => write!(f, "{}", host),
201 Self::K8sService(k8s_service) => write!(f, "{}", k8s_service),
202 Self::File { path } => write!(f, "{}", path),
203 }
204 }
205}
206
207impl Default for BackendHost {
208 fn default() -> Self {
209 Self::Host { host: String::default() }
210 }
211}