feat: implement Unix domain socket admin API for config reload and status
Add admin socket module that binds to a configurable Unix domain socket path (default /run/reverse-proxy/admin.sock) supporting reload and status commands. Reload re-reads config and swaps DynamicConfig via ArcSwap with serialized access using the same Mutex as SIGHUP. Status returns uptime and site count. Unknown commands and invalid input return structured JSON error responses. Stale socket files are removed at startup; if the socket is occupied by another process, a warning is logged and the socket is disabled. Empty admin_socket_path disables the socket entirely. Also adds FullConfig struct to config module for parsing complete config files during reload, and adds serde_json dependency for JSON responses.
This commit is contained in:
@@ -9,3 +9,50 @@ pub use dynamic_config::{
|
||||
};
|
||||
pub use static_config::{ListenerConfig, LoggingConfig, StaticConfig, TlsConfig};
|
||||
pub use validation::{validate, ValidationError};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct FullConfig {
|
||||
#[serde(default)]
|
||||
pub listeners: Vec<ListenerConfig>,
|
||||
#[serde(default)]
|
||||
pub allow_wildcard_bind: bool,
|
||||
#[serde(default = "static_config::default_health_check_port")]
|
||||
pub health_check_port: u16,
|
||||
#[serde(default = "static_config::default_admin_socket_path")]
|
||||
pub admin_socket_path: String,
|
||||
#[serde(default = "static_config::default_shutdown_timeout_secs")]
|
||||
pub shutdown_timeout_secs: u64,
|
||||
#[serde(default)]
|
||||
pub logging: LoggingConfig,
|
||||
pub rate_limit: RateLimitConfig,
|
||||
pub body: BodyConfig,
|
||||
}
|
||||
|
||||
impl FullConfig {
|
||||
pub fn parse(content: &str) -> anyhow::Result<Self> {
|
||||
Ok(toml::from_str(content)?)
|
||||
}
|
||||
|
||||
pub fn into_static_and_dynamic(self) -> (StaticConfig, DynamicConfig) {
|
||||
let static_config = StaticConfig {
|
||||
listeners: self.listeners,
|
||||
allow_wildcard_bind: self.allow_wildcard_bind,
|
||||
health_check_port: self.health_check_port,
|
||||
admin_socket_path: self.admin_socket_path,
|
||||
shutdown_timeout_secs: self.shutdown_timeout_secs,
|
||||
logging: self.logging,
|
||||
};
|
||||
let dynamic_config = DynamicConfig::from_sites(
|
||||
static_config
|
||||
.listeners
|
||||
.iter()
|
||||
.flat_map(|l| l.sites.clone())
|
||||
.collect(),
|
||||
self.rate_limit,
|
||||
self.body,
|
||||
);
|
||||
(static_config, dynamic_config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,15 @@ pub struct StaticConfig {
|
||||
pub logging: LoggingConfig,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn default_health_check_port() -> u16 {
|
||||
pub fn default_health_check_port() -> u16 {
|
||||
9900
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn default_admin_socket_path() -> String {
|
||||
pub fn default_admin_socket_path() -> String {
|
||||
"/run/reverse-proxy/admin.sock".to_string()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn default_shutdown_timeout_secs() -> u64 {
|
||||
pub fn default_shutdown_timeout_secs() -> u64 {
|
||||
30
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user