1use platform_core::{
2 AppContext, RuntimeConfigDescriptor, RuntimeConfigScope, RuntimeConfigSnapshot,
3 RuntimeConfigType,
4};
5use std::sync::LazyLock;
6use std::time::Duration;
7
8const SESSION_CACHE_KEY: &str = "auth.session_cache";
9
10pub const SESSION_CACHE_MAX_TTL: Duration = Duration::from_secs(12 * 60 * 60);
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum SessionCacheMode {
14 Database,
15 Redis,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct AuthRuntimeConfig {
20 pub session_cache: SessionCacheMode,
21}
22
23impl AuthRuntimeConfig {
24 #[must_use]
25 pub fn from_context(ctx: &AppContext) -> Self {
26 Self::from_snapshot(&ctx.runtime_config.snapshot())
27 }
28
29 #[must_use]
30 pub fn from_snapshot(snapshot: &RuntimeConfigSnapshot) -> Self {
31 let session_cache = snapshot
32 .raw(SESSION_CACHE_KEY)
33 .and_then(serde_json::Value::as_str)
34 .and_then(SessionCacheMode::from_value)
35 .unwrap_or(SessionCacheMode::Database);
36 Self { session_cache }
37 }
38}
39
40impl Default for AuthRuntimeConfig {
41 fn default() -> Self {
42 Self {
43 session_cache: SessionCacheMode::Database,
44 }
45 }
46}
47
48impl SessionCacheMode {
49 fn from_value(value: &str) -> Option<Self> {
50 match value {
51 "database" => Some(Self::Database),
52 "redis" => Some(Self::Redis),
53 _ => None,
54 }
55 }
56}
57
58pub static RUNTIME_CONFIG: LazyLock<Vec<RuntimeConfigDescriptor>> = LazyLock::new(|| {
59 vec![RuntimeConfigDescriptor {
60 key: SESSION_CACHE_KEY.to_owned(),
61 scope: RuntimeConfigScope::Shared,
62 group: None,
63 section: None,
64 order: 10,
65 visible_when: None,
66 generated: None,
67 value_type: RuntimeConfigType::Enum(&["database", "redis"]),
68 default: serde_json::json!("database"),
69 editable: true,
70 restart_only: true,
71 description: "Session cache backend used by auth session resolution.",
72 }]
73});
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use platform_core::{RuntimeConfigRegistry, RuntimeConfigSnapshot};
79 use std::collections::BTreeMap;
80
81 #[test]
82 fn defaults_to_database_cache() {
83 let registry = RuntimeConfigRegistry::try_new(RUNTIME_CONFIG.clone()).unwrap();
84 let snapshot = RuntimeConfigSnapshot::resolve(®istry, "api", &BTreeMap::new());
85
86 let config = AuthRuntimeConfig::from_snapshot(&snapshot);
87
88 assert_eq!(config.session_cache, SessionCacheMode::Database);
89 }
90}