spacegate_model/
gateway.rs

1use std::{fmt::Display, net::IpAddr};
2
3use serde::{Deserialize, Serialize};
4
5use super::plugin::PluginInstanceId;
6
7/// Gateway represents an instance of a service-traffic handling infrastructure
8/// by binding Listeners to a set of IP addresses.
9///
10/// Reference: [Kubernetes Gateway](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.Gateway)
11#[derive(Debug, Serialize, Deserialize, Clone)]
12#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
13#[serde(default)]
14/// Name of the Gateway. Global Unique.
15pub struct SgGateway<P = PluginInstanceId> {
16    pub name: String,
17    /// Some parameters necessary for the gateway.
18    pub parameters: SgParameters,
19    #[serde(skip_serializing_if = "Vec::is_empty")]
20    /// Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway’s addresses.
21    pub listeners: Vec<SgListener>,
22    #[serde(skip_serializing_if = "Vec::is_empty")]
23    /// Filters define the filters that are applied to requests that match this gateway.
24    pub plugins: Vec<P>,
25}
26
27impl<P> Default for SgGateway<P> {
28    fn default() -> Self {
29        Self {
30            name: Default::default(),
31            parameters: Default::default(),
32            listeners: Default::default(),
33            plugins: Default::default(),
34        }
35    }
36}
37
38impl<P> SgGateway<P> {
39    pub fn map_plugins<F, T>(self, f: F) -> SgGateway<T>
40    where
41        F: FnMut(P) -> T,
42    {
43        SgGateway {
44            name: self.name,
45            parameters: self.parameters,
46            listeners: self.listeners,
47            plugins: self.plugins.into_iter().map(f).collect(),
48        }
49    }
50}
51
52/// Gateway parameter configuration.
53#[derive(Default, Debug, Serialize, Deserialize, Clone)]
54#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
55#[serde(default)]
56pub struct SgParameters {
57    #[serde(skip_serializing_if = "Option::is_none")]
58    /// Redis access Url, Url with permission information.
59    pub redis_url: Option<String>,
60    #[serde(skip_serializing_if = "Option::is_none")]
61    /// Gateway Log_Level
62    pub log_level: Option<String>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    /// Gateway language
65    pub lang: Option<String>,
66    #[serde(skip_serializing_if = "Option::is_none")]
67    /// Ignore backend tls verification
68    pub ignore_tls_verification: Option<bool>,
69    #[serde(skip_serializing_if = "Option::is_none")]
70    /// Add request id for every request
71    pub enable_x_request_id: Option<bool>,
72}
73
74/// Listener embodies the concept of a logical endpoint where a Gateway accepts network connections.
75#[derive(Default, Debug, Serialize, Deserialize, Clone)]
76#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
77#[serde(default)]
78pub struct SgListener {
79    /// Name is the name of the Listener. This name MUST be unique within a Gateway.
80    pub name: String,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    /// Ip bound to the Listener. Default is 0.0.0.0
83    pub ip: Option<IpAddr>,
84    /// Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules.
85    pub port: u16,
86    /// Protocol specifies the network protocol this listener expects to receive.
87    pub protocol: SgProtocolConfig,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    /// `HostName` is used to define the host on which the listener accepts requests.
90    pub hostname: Option<String>,
91}
92
93#[non_exhaustive]
94/// ProtocolType defines the application protocol accepted by a Listener.
95#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
96#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)]
97#[serde(rename_all = "lowercase")]
98pub enum SgBackendProtocol {
99    /// Accepts cleartext HTTP/1.1 sessions over TCP. Implementations MAY also support HTTP/2 over cleartext.
100    /// If implementations support HTTP/2 over cleartext on “HTTP” listeners, that MUST be clearly documented by the implementation.
101    #[default]
102    Http,
103    /// Accepts HTTP/1.1 or HTTP/2 sessions over TLS.
104    Https,
105}
106
107impl Display for SgBackendProtocol {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        match self {
110            SgBackendProtocol::Http => write!(f, "http"),
111            SgBackendProtocol::Https { .. } => write!(f, "https"),
112        }
113    }
114}
115
116#[non_exhaustive]
117/// ProtocolType defines the application protocol accepted by a Listener.
118#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)]
119#[serde(rename_all = "lowercase", tag = "type")]
120#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
121pub enum SgProtocolConfig {
122    /// Accepts cleartext HTTP/1.1 sessions over TCP. Implementations MAY also support HTTP/2 over cleartext.
123    /// If implementations support HTTP/2 over cleartext on “HTTP” listeners, that MUST be clearly documented by the implementation.
124    #[default]
125    Http,
126    /// Accepts HTTP/1.1 or HTTP/2 sessions over TLS.
127    Https {
128        /// TLS is the TLS configuration for the Listener.
129        /// This field is required if the Protocol field is “HTTPS” or “TLS”. It is invalid to set this field if the Protocol field is “HTTP”, “TCP”, or “UDP”.
130        tls: SgTlsConfig,
131    },
132}
133
134impl Display for SgProtocolConfig {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        match self {
137            SgProtocolConfig::Http => write!(f, "http"),
138            SgProtocolConfig::Https { .. } => write!(f, "https"),
139        }
140    }
141}
142
143/// GatewayTLSConfig describes a TLS configuration.
144#[derive(Debug, Serialize, PartialEq, Eq, Deserialize, Clone)]
145#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
146pub struct SgTlsConfig {
147    pub mode: SgTlsMode,
148    pub key: String,
149    pub cert: String,
150    pub http2: Option<bool>,
151}
152
153#[derive(Debug, Serialize, PartialEq, Deserialize, Clone, Default, Eq, Copy)]
154#[cfg_attr(feature = "typegen", derive(ts_rs::TS), ts(export))]
155pub enum SgTlsMode {
156    Terminate,
157    #[default]
158    Passthrough,
159}
160
161impl From<SgTlsMode> for String {
162    fn from(value: SgTlsMode) -> Self {
163        match value {
164            SgTlsMode::Terminate => "Terminate".to_string(),
165            SgTlsMode::Passthrough => "Passthrough".to_string(),
166        }
167    }
168}
169
170impl From<String> for SgTlsMode {
171    fn from(value: String) -> Self {
172        match value.to_lowercase().as_str() {
173            "terminate" => SgTlsMode::Terminate,
174            "passthrough" => SgTlsMode::Passthrough,
175            _ => SgTlsMode::Passthrough,
176        }
177    }
178}
179
180impl From<Option<String>> for SgTlsMode {
181    fn from(value: Option<String>) -> Self {
182        SgTlsMode::from(value.unwrap_or_default())
183    }
184}
185
186impl SgTlsMode {
187    pub fn to_pascal_case(&self) -> &'static str {
188        match self {
189            SgTlsMode::Terminate => "Terminate",
190            SgTlsMode::Passthrough => "Passthrough",
191        }
192    }
193}