use std::time::Duration; use serde::{Deserialize, Serialize}; pub const DEFAULT_LISTEN_ADDRESS: &str = "0.0.0.0:7031"; pub const MIN_HEARTBEAT_INTERVAL_SECS: u64 = 30; pub const MAX_HEARTBEAT_GAP_SECS: u64 = 60; pub const DEFAULT_HEARTBEAT_TIMEOUT_SECS: u64 = 30; pub const DEFAULT_AUTH_TIMEOUT_SECS: u64 = 5; pub const DEFAULT_MAX_PAYLOAD: usize = 1_000_000; /// KenApi 会话 cookie 名(`session.cookie_name`),event 只读不写。 pub const DEFAULT_SESSION_COOKIE: &str = "session"; #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(default)] pub struct SocketConfig { pub listen_address: String, pub heartbeat_interval_secs: u64, pub heartbeat_timeout_secs: u64, pub auth_timeout_secs: u64, pub max_payload: usize, pub session_cookie: String, } impl SocketConfig { pub fn heartbeat_interval(&self) -> Duration { Duration::from_secs(self.heartbeat_interval_secs) } pub fn heartbeat_timeout(&self) -> Duration { Duration::from_secs(self.heartbeat_timeout_secs) } pub fn auth_timeout(&self) -> Duration { Duration::from_secs(self.auth_timeout_secs) } pub fn validate(&self) -> Result<(), String> { if self.listen_address.trim().is_empty() { return Err("event.socket.listen_address must not be blank".to_string()); } if self.heartbeat_interval_secs < MIN_HEARTBEAT_INTERVAL_SECS { return Err("event.socket.heartbeat_interval_secs must be at least 30".to_string()); } if self.heartbeat_timeout_secs == 0 { return Err( "event.socket.heartbeat_timeout_secs must be greater than zero".to_string(), ); } let gap = self .heartbeat_interval_secs .checked_add(self.heartbeat_timeout_secs) .ok_or_else(|| "event.socket heartbeat durations overflow".to_string())?; if gap > MAX_HEARTBEAT_GAP_SECS { return Err( "event.socket heartbeat interval plus timeout must not exceed 60 seconds" .to_string(), ); } if self.auth_timeout_secs == 0 { return Err("event.socket.auth_timeout_secs must be greater than zero".to_string()); } if self.max_payload == 0 { return Err("event.socket.max_payload must be greater than zero".to_string()); } if self.session_cookie.trim().is_empty() { return Err("event.socket.session_cookie must not be blank".to_string()); } Ok(()) } } impl Default for SocketConfig { fn default() -> Self { Self { listen_address: DEFAULT_LISTEN_ADDRESS.to_string(), heartbeat_interval_secs: MIN_HEARTBEAT_INTERVAL_SECS, heartbeat_timeout_secs: DEFAULT_HEARTBEAT_TIMEOUT_SECS, auth_timeout_secs: DEFAULT_AUTH_TIMEOUT_SECS, max_payload: DEFAULT_MAX_PAYLOAD, session_cookie: DEFAULT_SESSION_COOKIE.to_string(), } } }