use serde::{Deserialize, Serialize};
use std::time::Duration;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(clippy::struct_excessive_bools)]
pub struct HttpServerConfig {
pub bind_address: String,
#[serde(default = "default_request_timeout_ms")]
pub request_timeout_ms: u64,
#[serde(default = "default_keep_alive_timeout_ms")]
pub keep_alive_timeout_ms: u64,
#[serde(default = "default_max_connections")]
pub max_connections: usize,
#[serde(default = "default_true")]
pub enable_health_endpoints: bool,
#[serde(default)]
pub enable_metrics_endpoint: bool,
#[serde(default)]
pub enable_config_endpoint: bool,
#[serde(default = "default_true")]
pub enable_http2: bool,
#[serde(default)]
pub tls_cert_path: Option<String>,
#[serde(default)]
pub tls_key_path: Option<String>,
#[serde(default = "default_shutdown_timeout_ms")]
pub shutdown_timeout_ms: u64,
}
fn default_request_timeout_ms() -> u64 {
30_000
}
fn default_keep_alive_timeout_ms() -> u64 {
75_000
}
fn default_max_connections() -> usize {
10_000
}
fn default_shutdown_timeout_ms() -> u64 {
30_000
}
fn default_true() -> bool {
true
}
impl Default for HttpServerConfig {
fn default() -> Self {
Self {
bind_address: "0.0.0.0:8080".to_string(),
request_timeout_ms: default_request_timeout_ms(),
keep_alive_timeout_ms: default_keep_alive_timeout_ms(),
max_connections: default_max_connections(),
enable_health_endpoints: true,
enable_metrics_endpoint: false,
enable_config_endpoint: false,
enable_http2: true,
tls_cert_path: None,
tls_key_path: None,
shutdown_timeout_ms: default_shutdown_timeout_ms(),
}
}
}
impl HttpServerConfig {
#[must_use]
pub fn new(bind_address: impl Into<String>) -> Self {
Self {
bind_address: bind_address.into(),
..Default::default()
}
}
#[must_use]
pub fn request_timeout(&self) -> Duration {
Duration::from_millis(self.request_timeout_ms)
}
#[must_use]
pub fn keep_alive_timeout(&self) -> Duration {
Duration::from_millis(self.keep_alive_timeout_ms)
}
#[must_use]
pub fn shutdown_timeout(&self) -> Duration {
Duration::from_millis(self.shutdown_timeout_ms)
}
#[must_use]
pub fn is_tls_enabled(&self) -> bool {
self.tls_cert_path.is_some() && self.tls_key_path.is_some()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = HttpServerConfig::default();
assert_eq!(config.bind_address, "0.0.0.0:8080");
assert_eq!(config.request_timeout_ms, 30_000);
assert_eq!(config.keep_alive_timeout_ms, 75_000);
assert_eq!(config.max_connections, 10_000);
assert!(config.enable_health_endpoints);
assert!(!config.enable_metrics_endpoint);
assert!(config.enable_http2);
assert!(!config.is_tls_enabled());
}
#[test]
fn test_new_with_address() {
let config = HttpServerConfig::new("127.0.0.1:3000");
assert_eq!(config.bind_address, "127.0.0.1:3000");
}
#[test]
fn test_tls_enabled() {
let mut config = HttpServerConfig::default();
assert!(!config.is_tls_enabled());
config.tls_cert_path = Some("/path/to/cert.pem".to_string());
assert!(!config.is_tls_enabled());
config.tls_key_path = Some("/path/to/key.pem".to_string());
assert!(config.is_tls_enabled());
}
#[test]
fn test_duration_conversions() {
let config = HttpServerConfig::default();
assert_eq!(config.request_timeout(), Duration::from_secs(30));
assert_eq!(config.keep_alive_timeout(), Duration::from_secs(75));
assert_eq!(config.shutdown_timeout(), Duration::from_secs(30));
}
}