Skip to main content

sqry_core/session/
config.rs

1//! Session configuration options.
2//!
3//! This module defines [`SessionConfig`], which controls how the session
4//! caching layer behaves (cache sizing, idle eviction, etc.). Defaults are
5//! tuned for local development workloads but can be overridden via
6//! environment variables to support larger repositories or CI scenarios.
7
8use std::time::Duration;
9
10/// Configuration options for the session cache.
11#[derive(Debug, Clone)]
12pub struct SessionConfig {
13    /// Maximum number of symbol indexes retained in-memory.
14    pub max_cached_indexes: usize,
15    /// How long an index can remain idle before eviction.
16    pub idle_timeout: Duration,
17    /// Whether filesystem watching is enabled for automatic invalidation.
18    pub enable_file_watching: bool,
19    /// Interval between background cleanup passes.
20    pub cleanup_interval: Duration,
21}
22
23impl Default for SessionConfig {
24    fn default() -> Self {
25        Self {
26            max_cached_indexes: 5,
27            idle_timeout: Duration::from_secs(60),
28            enable_file_watching: true,
29            cleanup_interval: Duration::from_secs(10),
30        }
31    }
32}
33
34impl SessionConfig {
35    /// Create a configuration using environment overrides when present.
36    ///
37    /// Supported environment variables:
38    ///
39    /// * `SQRY_SESSION_CACHE_SIZE` – maximum cached indexes (usize)
40    /// * `SQRY_SESSION_TIMEOUT` – idle timeout in seconds (u64)
41    /// * `SQRY_SESSION_CLEANUP_INTERVAL` – cleanup interval in seconds (u64)
42    /// * `SQRY_NO_SESSION` – disable session features when set to `1`
43    #[must_use]
44    pub fn from_env() -> Self {
45        Self::from_lookup(|key| std::env::var(key).ok())
46    }
47
48    /// Apply overrides using a custom environment lookup function (tests only).
49    fn from_lookup<F>(mut lookup: F) -> Self
50    where
51        F: FnMut(&str) -> Option<String>,
52    {
53        let mut config = Self::default();
54
55        if let Some(size) = lookup("SQRY_SESSION_CACHE_SIZE")
56            && let Ok(parsed) = size.parse::<usize>()
57        {
58            config.max_cached_indexes = parsed.max(1);
59        }
60
61        if let Some(timeout) = lookup("SQRY_SESSION_TIMEOUT")
62            && let Ok(secs) = timeout.parse::<u64>()
63        {
64            config.idle_timeout = Duration::from_secs(secs.max(1));
65        }
66
67        if let Some(interval) = lookup("SQRY_SESSION_CLEANUP_INTERVAL")
68            && let Ok(secs) = interval.parse::<u64>()
69        {
70            config.cleanup_interval = Duration::from_secs(secs.max(1));
71        }
72
73        if let Some(val) = lookup("SQRY_NO_SESSION") {
74            config.enable_file_watching = val != "1";
75        }
76
77        config
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn defaults_are_sane() {
87        let cfg = SessionConfig::default();
88        assert_eq!(cfg.max_cached_indexes, 5);
89        assert_eq!(cfg.idle_timeout, Duration::from_secs(60));
90        assert_eq!(cfg.cleanup_interval, Duration::from_secs(10));
91        assert!(cfg.enable_file_watching);
92    }
93
94    #[test]
95    fn env_overrides_apply() {
96        let cfg = SessionConfig::from_lookup(|key| match key {
97            "SQRY_SESSION_CACHE_SIZE" => Some("10".into()),
98            "SQRY_SESSION_TIMEOUT" => Some("120".into()),
99            "SQRY_SESSION_CLEANUP_INTERVAL" => Some("30".into()),
100            "SQRY_NO_SESSION" => Some("1".into()),
101            _ => None,
102        });
103        assert_eq!(cfg.max_cached_indexes, 10);
104        assert_eq!(cfg.idle_timeout, Duration::from_secs(120));
105        assert_eq!(cfg.cleanup_interval, Duration::from_secs(30));
106        assert!(!cfg.enable_file_watching);
107    }
108
109    #[test]
110    fn invalid_env_values_fall_back_to_defaults() {
111        let cfg = SessionConfig::from_lookup(|key| match key {
112            "SQRY_SESSION_CACHE_SIZE" => Some("not-a-number".into()),
113            "SQRY_SESSION_TIMEOUT" => Some("zero".into()),
114            "SQRY_SESSION_CLEANUP_INTERVAL" => Some("oops".into()),
115            _ => None,
116        });
117        assert_eq!(
118            cfg.max_cached_indexes,
119            SessionConfig::default().max_cached_indexes
120        );
121        assert_eq!(cfg.idle_timeout, SessionConfig::default().idle_timeout);
122        assert_eq!(
123            cfg.cleanup_interval,
124            SessionConfig::default().cleanup_interval
125        );
126    }
127}