use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum Protocol {
#[default]
Http,
Tcp,
Udp,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EntrypointConfig {
pub address: String,
#[serde(default)]
pub protocol: Protocol,
#[serde(default)]
pub tls: Option<TlsConfig>,
#[serde(default)]
pub max_connections: Option<u32>,
#[serde(default)]
pub tcp_allowed_ips: Vec<String>,
#[serde(default)]
pub udp_session_timeout_secs: Option<u64>,
#[serde(default)]
pub udp_max_sessions: Option<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
pub cert_file: String,
pub key_file: String,
#[serde(default)]
pub acme: bool,
#[serde(default = "default_min_tls_version")]
pub min_version: String,
#[serde(default)]
pub acme_email: Option<String>,
#[serde(default)]
pub acme_domains: Vec<String>,
#[serde(default)]
pub acme_staging: bool,
#[serde(default)]
pub acme_storage_path: Option<String>,
}
fn default_min_tls_version() -> String {
"1.2".to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_protocol_default() {
assert_eq!(Protocol::default(), Protocol::Http);
}
#[test]
fn test_protocol_serialization() {
let json = serde_json::to_string(&Protocol::Tcp).unwrap();
assert_eq!(json, "\"tcp\"");
let parsed: Protocol = serde_json::from_str("\"udp\"").unwrap();
assert_eq!(parsed, Protocol::Udp);
}
#[test]
fn test_entrypoint_parse() {
let hcl = r#"
address = "0.0.0.0:80"
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
assert_eq!(ep.address, "0.0.0.0:80");
assert_eq!(ep.protocol, Protocol::Http);
assert!(ep.tls.is_none());
}
#[test]
fn test_entrypoint_with_tls() {
let hcl = r#"
address = "0.0.0.0:443"
tls {
cert_file = "/etc/certs/cert.pem"
key_file = "/etc/certs/key.pem"
}
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
let tls = ep.tls.unwrap();
assert_eq!(tls.cert_file, "/etc/certs/cert.pem");
assert_eq!(tls.key_file, "/etc/certs/key.pem");
assert!(!tls.acme);
assert_eq!(tls.min_version, "1.2");
}
#[test]
fn test_entrypoint_tcp_protocol() {
let hcl = r#"
address = "0.0.0.0:9000"
protocol = "tcp"
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
assert_eq!(ep.protocol, Protocol::Tcp);
}
#[test]
fn test_entrypoint_udp_protocol() {
let hcl = r#"
address = "0.0.0.0:9001"
protocol = "udp"
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
assert_eq!(ep.protocol, Protocol::Udp);
}
#[test]
fn test_entrypoint_tcp_with_filter() {
let hcl = r#"
address = "0.0.0.0:9000"
protocol = "tcp"
max_connections = 1000
tcp_allowed_ips = ["10.0.0.0/8", "192.168.1.1"]
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
assert_eq!(ep.protocol, Protocol::Tcp);
assert_eq!(ep.max_connections.unwrap(), 1000);
assert_eq!(ep.tcp_allowed_ips.len(), 2);
}
#[test]
fn test_entrypoint_defaults_no_tcp_filter() {
let hcl = r#"
address = "0.0.0.0:80"
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
assert!(ep.max_connections.is_none());
assert!(ep.tcp_allowed_ips.is_empty());
}
#[test]
fn test_entrypoint_udp_with_config() {
let hcl = r#"
address = "0.0.0.0:9001"
protocol = "udp"
udp_session_timeout_secs = 60
udp_max_sessions = 5000
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
assert_eq!(ep.protocol, Protocol::Udp);
assert_eq!(ep.udp_session_timeout_secs, Some(60));
assert_eq!(ep.udp_max_sessions, Some(5000));
}
#[test]
fn test_entrypoint_udp_defaults() {
let hcl = r#"
address = "0.0.0.0:9001"
protocol = "udp"
"#;
let ep: EntrypointConfig = hcl::from_str(hcl).unwrap();
assert_eq!(ep.protocol, Protocol::Udp);
assert!(ep.udp_session_timeout_secs.is_none());
assert!(ep.udp_max_sessions.is_none());
}
#[test]
fn test_tls_acme_enabled() {
let hcl = r#"
cert_file = "/tmp/cert.pem"
key_file = "/tmp/key.pem"
acme = true
min_version = "1.3"
"#;
let tls: TlsConfig = hcl::from_str(hcl).unwrap();
assert!(tls.acme);
assert_eq!(tls.min_version, "1.3");
}
}