use serde::Deserialize; use std::time::Duration; mod duration_secs { use serde::{Deserialize, Deserializer}; use std::time::Duration; pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { u64::deserialize(deserializer).map(Duration::from_secs) } } mod opt_duration_secs { use serde::{Deserialize, Deserializer}; use std::time::Duration; pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { Option::::deserialize(deserializer).map(|o| o.map(Duration::from_secs)) } } #[derive(Clone, Debug, Deserialize)] #[serde(default)] pub struct GitConfig { pub repo_root: String, pub objects_root: String, pub max_blob_size: u64, pub git_command_timeout_secs: u64, pub git_rpc_timeout_secs: u64, pub sync: SyncSettings, pub ssh: GitSshConfig, pub base_url: String, } impl Default for GitConfig { fn default() -> Self { Self { repo_root: "/opt/gitdata/repos".to_string(), objects_root: "/opt/gitdata/objects".to_string(), max_blob_size: 100 * 1024 * 1024, git_command_timeout_secs: 300, git_rpc_timeout_secs: 3600, sync: SyncSettings::default(), ssh: GitSshConfig::default(), base_url: "http://localhost:3000".to_string(), } } } #[derive(Clone, Debug, Deserialize)] #[serde(default)] pub struct GitSshConfig { pub bind_addr: String, pub port: u16, pub host_key_path: String, pub banner: Option, pub max_sessions: usize, #[serde(deserialize_with = "duration_secs::deserialize")] pub auth_rejection_time: Duration, #[serde(deserialize_with = "opt_duration_secs::deserialize")] pub inactivity_timeout: Option, #[serde(deserialize_with = "duration_secs::deserialize")] pub keepalive_interval: Duration, pub keepalive_max: u32, } impl Default for GitSshConfig { fn default() -> Self { Self { bind_addr: "0.0.0.0".to_string(), port: 22, host_key_path: "/opt/gitdata/ssh_host_ed25519".to_string(), banner: None, max_sessions: 64, auth_rejection_time: Duration::from_secs(2), inactivity_timeout: Some(Duration::from_secs(300)), keepalive_interval: Duration::from_secs(30), keepalive_max: 3, } } } #[derive(Clone, Debug, Deserialize)] #[serde(default)] pub struct SyncSettings { pub lock_ttl_secs: u64, pub max_commits_per_sync: usize, pub concurrency: usize, pub queue_topic: String, pub dlq_topic: String, pub max_lock_retries: u64, pub max_languages: usize, pub language_timeout_secs: u64, pub brpop_timeout_secs: u64, pub git_command_timeout_secs: u64, } impl Default for SyncSettings { fn default() -> Self { Self { lock_ttl_secs: 120, max_commits_per_sync: 5_000, concurrency: 4, queue_topic: "gitdata:tasks".to_string(), dlq_topic: "gitdata:dlq".to_string(), max_lock_retries: 5, max_languages: 20, language_timeout_secs: 30, brpop_timeout_secs: 5, git_command_timeout_secs: 120, } } }