use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
pub host: String,
pub port: u16,
pub max_connections: usize,
pub request_timeout_secs: u64,
pub body_limit_bytes: usize,
pub enable_cors: bool,
pub cors_allowed_origins: Vec<String>,
pub tls: Option<TlsConfig>,
pub cluster_tls: Option<ClusterTlsConfig>,
pub data_dir: Option<String>,
pub node_id: String,
pub node_name: Option<String>,
pub cluster_name: String,
pub peers: Vec<String>,
pub rate_limit_per_minute: u32,
pub login_rate_limit_per_minute: u32,
pub auth_required: bool,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
host: "127.0.0.1".to_string(),
port: 3000,
max_connections: 10000,
request_timeout_secs: 30,
body_limit_bytes: 10 * 1024 * 1024, enable_cors: true,
cors_allowed_origins: Vec::new(), tls: None,
cluster_tls: None,
data_dir: None,
node_id: generate_node_id(),
node_name: None,
cluster_name: "aegis-cluster".to_string(),
peers: Vec::new(),
rate_limit_per_minute: 100,
login_rate_limit_per_minute: 30,
auth_required: true,
}
}
}
fn generate_node_id() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis();
format!("node-{:x}", timestamp as u64)
}
impl ServerConfig {
pub fn new(host: &str, port: u16) -> Self {
Self {
host: host.to_string(),
port,
..Default::default()
}
}
pub fn socket_addr(&self) -> SocketAddr {
format!("{}:{}", self.host, self.port)
.parse()
.unwrap_or_else(|_| SocketAddr::from(([127, 0, 0, 1], self.port)))
}
pub fn with_tls(mut self, cert_path: &str, key_path: &str) -> Self {
self.tls = Some(TlsConfig {
cert_path: cert_path.to_string(),
key_path: key_path.to_string(),
});
self
}
pub fn with_max_connections(mut self, max: usize) -> Self {
self.max_connections = max;
self
}
pub fn with_timeout(mut self, secs: u64) -> Self {
self.request_timeout_secs = secs;
self
}
pub fn with_data_dir(mut self, data_dir: Option<String>) -> Self {
self.data_dir = data_dir;
self
}
pub fn with_node_id(mut self, node_id: Option<String>) -> Self {
if let Some(id) = node_id {
self.node_id = id;
}
self
}
pub fn with_node_name(mut self, node_name: Option<String>) -> Self {
self.node_name = node_name;
self
}
pub fn with_cluster_name(mut self, cluster_name: String) -> Self {
self.cluster_name = cluster_name;
self
}
pub fn with_peers(mut self, peers: Vec<String>) -> Self {
self.peers = peers;
self
}
pub fn address(&self) -> String {
format!("{}:{}", self.host, self.port)
}
pub fn with_cluster_tls(mut self, cluster_tls: Option<ClusterTlsConfig>) -> Self {
self.cluster_tls = cluster_tls;
self
}
pub fn cluster_tls_enabled(&self) -> bool {
self.cluster_tls.as_ref().is_some_and(|c| c.enabled)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
pub cert_path: String,
pub key_path: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClusterTlsConfig {
pub enabled: bool,
pub ca_cert_path: Option<String>,
pub client_cert_path: Option<String>,
pub client_key_path: Option<String>,
pub danger_accept_invalid_certs: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = ServerConfig::default();
assert_eq!(config.host, "127.0.0.1");
assert_eq!(config.port, 3000);
assert!(config.tls.is_none());
}
#[test]
fn test_socket_addr() {
let config = ServerConfig::new("0.0.0.0", 8080);
let addr = config.socket_addr();
assert_eq!(addr.port(), 8080);
}
#[test]
fn test_cluster_tls_config() {
let config = ServerConfig::default();
assert!(!config.cluster_tls_enabled());
let config_with_tls = config.with_cluster_tls(Some(ClusterTlsConfig {
enabled: true,
ca_cert_path: Some("/path/to/ca.pem".to_string()),
client_cert_path: Some("/path/to/cert.pem".to_string()),
client_key_path: Some("/path/to/key.pem".to_string()),
danger_accept_invalid_certs: false,
}));
assert!(config_with_tls.cluster_tls_enabled());
let config_disabled = ServerConfig::default().with_cluster_tls(Some(ClusterTlsConfig {
enabled: false,
ca_cert_path: None,
client_cert_path: None,
client_key_path: None,
danger_accept_invalid_certs: false,
}));
assert!(!config_disabled.cluster_tls_enabled());
}
}