flowgate/src/config.rs

134 lines
4.1 KiB
Rust
Executable File

use std::{fs, time::Duration};
use std::net::TcpStream;
use serde_yml::{Number, Value};
use wildmatch::WildMatch;
use super::tls::TlsCertificate;
#[derive(Clone, Debug)]
pub struct SiteConfig {
pub domain: WildMatch,
pub host: String,
pub ssl: Option<TlsCertificate>,
pub enable_keep_alive: bool,
pub support_keep_alive: bool,
pub ip_forwarding: IpForwarding,
pub replace_host: Option<String>
}
impl SiteConfig {
pub fn connect(&self) -> Option<TcpStream> {
TcpStream::connect(self.host.clone()).ok()
}
}
#[derive(Clone, Debug)]
pub enum IpForwarding {
Simple,
Header(String),
Modern,
None
}
impl IpForwarding {
pub fn from_name(name: &str) -> Option<IpForwarding> {
match name {
"none" => Some(IpForwarding::None),
"simple" => Some(IpForwarding::Simple),
"modern" => Some(IpForwarding::Modern),
"header" => Some(IpForwarding::Header(String::from("X-Real-IP"))),
name => if name.starts_with("header:") {
Some(IpForwarding::Header(name[7..].to_string()))
} else {
None
}
}
}
}
#[derive(Clone, Debug)]
pub struct Config {
pub sites: Vec<SiteConfig>,
pub http_host: Option<String>,
pub https_host: Option<String>,
pub connection_timeout: Duration,
pub incoming_ip_forwarding: IpForwarding,
pub threadpool_size: usize
}
impl Config {
pub fn parse(filename: &str) -> Option<Config> {
let file_content = fs::read_to_string(filename).ok()?;
let doc = serde_yml::from_str::<Value>(file_content.as_str()).ok()?;
let http_host = doc.get("http_host").and_then(|o| Some(o.as_str()?.to_string()));
let https_host = doc.get("https_host").and_then(|o| Some(o.as_str()?.to_string()));
let threadpool_size = doc.get("threadpool_size").and_then(|o| Some(o.as_u64()? as usize + 2)).unwrap_or(12);
let connection_timeout = Duration::from_secs(doc.get("connection_timeout")
.unwrap_or(&Value::Number(Number::from(10))).as_u64()?);
let incoming_ip_forwarding = doc.get("incoming_ip_forwarding")
.map(|o| o.as_str()).flatten()
.map(|o| IpForwarding::from_name(o)).flatten()
.unwrap_or(IpForwarding::None);
let mut sites: Vec<SiteConfig> = Vec::new();
let sites_yaml = doc["sites"].as_sequence()?;
for s in sites_yaml {
let mut cert: Option<TlsCertificate> = None;
let s = s.as_mapping()?;
if s.contains_key("ssl_cert") {
cert = Some(
TlsCertificate::new(
s.get("ssl_cert")?.as_str()?,
s.get("ssl_key")?.as_str()?,
)?,
);
}
let site = SiteConfig {
domain: WildMatch::new(&s.get("domain")?.as_str()?.to_string()),
host: s.get("host")?.as_str()?.to_string(),
ssl: cert,
enable_keep_alive: s.get("enable_keep_alive")
.map(|o| o.as_bool().unwrap())
.unwrap_or(true),
support_keep_alive: s.get("support_keep_alive")
.map(|o| o.as_bool().unwrap())
.unwrap_or(true),
ip_forwarding: s.get("ip_forwarding")
.map(|o| o.as_str()).flatten()
.map(|o| IpForwarding::from_name(o)).flatten()
.unwrap_or(IpForwarding::Header("X-Real-IP".to_string())),
replace_host: s.get("replace_host")
.map(|o| o.as_str()).flatten().map(|o| o.to_string()),
};
sites.push(site);
}
Some(Config {
sites,
http_host,
https_host,
connection_timeout,
incoming_ip_forwarding,
threadpool_size
}.clone())
}
pub fn get_site(&self, domain: &str) -> Option<&SiteConfig> {
for i in &self.sites {
if i.domain.matches(domain) {
return Some(i);
}
}
return None;
}
}