From 6b9c7f7862da68da45446faa7e848e465e87900b Mon Sep 17 00:00:00 2001 From: Alexey <247128645+axkurcom@users.noreply.github.com> Date: Wed, 4 Mar 2026 02:46:12 +0300 Subject: [PATCH] Runtime API in defaults Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com> --- src/config/defaults.rs | 8 ++++++++ src/config/hot_reload.rs | 3 +++ src/config/load.rs | 44 ++++++++++++++++++++++++++++++++++++++++ src/config/types.rs | 10 +++++++++ 4 files changed, 65 insertions(+) diff --git a/src/config/defaults.rs b/src/config/defaults.rs index d5eed59..86f569b 100644 --- a/src/config/defaults.rs +++ b/src/config/defaults.rs @@ -104,6 +104,14 @@ pub(crate) fn default_api_request_body_limit_bytes() -> usize { 64 * 1024 } +pub(crate) fn default_api_minimal_runtime_enabled() -> bool { + false +} + +pub(crate) fn default_api_minimal_runtime_cache_ttl_ms() -> u64 { + 1000 +} + pub(crate) fn default_prefer_4() -> u8 { 4 } diff --git a/src/config/hot_reload.rs b/src/config/hot_reload.rs index 29a6d70..d752d45 100644 --- a/src/config/hot_reload.rs +++ b/src/config/hot_reload.rs @@ -120,6 +120,9 @@ fn warn_non_hot_changes(old: &ProxyConfig, new: &ProxyConfig) { || old.server.api.whitelist != new.server.api.whitelist || old.server.api.auth_header != new.server.api.auth_header || old.server.api.request_body_limit_bytes != new.server.api.request_body_limit_bytes + || old.server.api.minimal_runtime_enabled != new.server.api.minimal_runtime_enabled + || old.server.api.minimal_runtime_cache_ttl_ms + != new.server.api.minimal_runtime_cache_ttl_ms || old.server.api.read_only != new.server.api.read_only { warn!("config reload: server.api changed; restart required"); diff --git a/src/config/load.rs b/src/config/load.rs index 825824d..b469299 100644 --- a/src/config/load.rs +++ b/src/config/load.rs @@ -404,6 +404,12 @@ impl ProxyConfig { )); } + if config.server.api.minimal_runtime_cache_ttl_ms > 60_000 { + return Err(ProxyError::Config( + "server.api.minimal_runtime_cache_ttl_ms must be within [0, 60000]".to_string(), + )); + } + if config.server.api.listen.parse::().is_err() { return Err(ProxyError::Config( "server.api.listen must be in IP:PORT format".to_string(), @@ -713,6 +719,14 @@ mod tests { cfg.server.api.request_body_limit_bytes, default_api_request_body_limit_bytes() ); + assert_eq!( + cfg.server.api.minimal_runtime_enabled, + default_api_minimal_runtime_enabled() + ); + assert_eq!( + cfg.server.api.minimal_runtime_cache_ttl_ms, + default_api_minimal_runtime_cache_ttl_ms() + ); assert_eq!(cfg.access.users, default_access_users()); } @@ -800,6 +814,14 @@ mod tests { server.api.request_body_limit_bytes, default_api_request_body_limit_bytes() ); + assert_eq!( + server.api.minimal_runtime_enabled, + default_api_minimal_runtime_enabled() + ); + assert_eq!( + server.api.minimal_runtime_cache_ttl_ms, + default_api_minimal_runtime_cache_ttl_ms() + ); let access = AccessConfig::default(); assert_eq!(access.users, default_access_users()); @@ -1346,6 +1368,28 @@ mod tests { let _ = std::fs::remove_file(path); } + #[test] + fn api_minimal_runtime_cache_ttl_out_of_range_is_rejected() { + let toml = r#" + [server.api] + enabled = true + listen = "127.0.0.1:9091" + minimal_runtime_cache_ttl_ms = 70000 + + [censorship] + tls_domain = "example.com" + + [access.users] + user = "00000000000000000000000000000000" + "#; + let dir = std::env::temp_dir(); + let path = dir.join("telemt_api_minimal_runtime_cache_ttl_invalid_test.toml"); + std::fs::write(&path, toml).unwrap(); + let err = ProxyConfig::load(&path).unwrap_err().to_string(); + assert!(err.contains("server.api.minimal_runtime_cache_ttl_ms must be within [0, 60000]")); + let _ = std::fs::remove_file(path); + } + #[test] fn force_close_bumped_when_below_drain_ttl() { let toml = r#" diff --git a/src/config/types.rs b/src/config/types.rs index dfb6b89..ee17108 100644 --- a/src/config/types.rs +++ b/src/config/types.rs @@ -817,6 +817,14 @@ pub struct ApiConfig { #[serde(default = "default_api_request_body_limit_bytes")] pub request_body_limit_bytes: usize, + /// Enable runtime snapshots that require read-lock aggregation on API request path. + #[serde(default = "default_api_minimal_runtime_enabled")] + pub minimal_runtime_enabled: bool, + + /// Cache TTL for minimal runtime snapshots in milliseconds (0 disables caching). + #[serde(default = "default_api_minimal_runtime_cache_ttl_ms")] + pub minimal_runtime_cache_ttl_ms: u64, + /// Read-only mode: mutating endpoints are rejected. #[serde(default)] pub read_only: bool, @@ -830,6 +838,8 @@ impl Default for ApiConfig { whitelist: default_api_whitelist(), auth_header: String::new(), request_body_limit_bytes: default_api_request_body_limit_bytes(), + minimal_runtime_enabled: default_api_minimal_runtime_enabled(), + minimal_runtime_cache_ttl_ms: default_api_minimal_runtime_cache_ttl_ms(), read_only: false, } }