use serde::{Deserialize, Serialize};
use std::sync::OnceLock;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct EnvLessBridgeConfig {
pub init_retry_max_attempts: u32,
pub init_retry_base_delay_ms: u64,
pub init_retry_jitter_fraction: f64,
pub init_retry_max_delay_ms: u64,
pub http_timeout_ms: u64,
pub uuid_dedup_buffer_size: u32,
pub heartbeat_interval_ms: u64,
pub heartbeat_jitter_fraction: f64,
pub token_refresh_buffer_ms: u64,
pub teardown_archive_timeout_ms: u64,
pub connect_timeout_ms: u64,
pub min_version: &'static str,
pub should_show_app_upgrade_message: bool,
}
pub const DEFAULT_ENV_LESS_BRIDGE_CONFIG: EnvLessBridgeConfig = EnvLessBridgeConfig {
init_retry_max_attempts: 3,
init_retry_base_delay_ms: 500,
init_retry_jitter_fraction: 0.25,
init_retry_max_delay_ms: 4000,
http_timeout_ms: 10_000,
uuid_dedup_buffer_size: 2000,
heartbeat_interval_ms: 20_000,
heartbeat_jitter_fraction: 0.1,
token_refresh_buffer_ms: 300_000,
teardown_archive_timeout_ms: 1500,
connect_timeout_ms: 15_000,
min_version: &"0.0.0",
should_show_app_upgrade_message: false,
};
static ENV_LESS_BRIDGE_CONFIG: OnceLock<EnvLessBridgeConfig> = OnceLock::new();
fn get_current_version() -> String {
env!("CARGO_PKG_VERSION").to_string()
}
fn version_lt(a: &str, b: &str) -> bool {
let a_parts: Vec<u32> = a.split('.').filter_map(|s| s.parse().ok()).collect();
let b_parts: Vec<u32> = b.split('.').filter_map(|s| s.parse().ok()).collect();
for (av, bv) in a_parts.iter().zip(b_parts.iter()) {
if av < bv {
return true;
}
if av > bv {
return false;
}
}
false
}
pub async fn get_env_less_bridge_config() -> EnvLessBridgeConfig {
ENV_LESS_BRIDGE_CONFIG
.get_or_init(|| DEFAULT_ENV_LESS_BRIDGE_CONFIG.clone())
.clone()
}
pub async fn check_env_less_bridge_min_version() -> Option<String> {
let cfg = get_env_less_bridge_config().await;
if !cfg.min_version.is_empty() && version_lt(&get_current_version(), &cfg.min_version) {
return Some(format!(
"Your version of AI Code ({}) is too old for Remote Control.\n\
Version {} or higher is required. Run `ai update` to update.",
get_current_version(),
cfg.min_version
));
}
None
}
pub async fn should_show_app_upgrade_message() -> bool {
if !crate::bridge_enabled::is_env_less_bridge_enabled() {
return false;
}
let cfg = get_env_less_bridge_config().await;
cfg.should_show_app_upgrade_message
}