Skip to main content

eero_api/credential/
memory.rs

1use std::sync::{Arc, Mutex};
2
3use crate::error::Result;
4
5use super::CredentialStore;
6
7/// An in-memory credential store backed by `Arc<Mutex<…>>`.
8///
9/// Useful when a session token is provided externally (e.g. via CLI flag or
10/// environment variable) and should not be persisted to disk.
11#[derive(Clone)]
12pub struct InMemoryStore {
13    session: Arc<Mutex<Option<String>>>,
14    user: Arc<Mutex<Option<String>>>,
15}
16
17impl InMemoryStore {
18    pub fn new() -> Self {
19        Self {
20            session: Arc::new(Mutex::new(None)),
21            user: Arc::new(Mutex::new(None)),
22        }
23    }
24}
25
26impl Default for InMemoryStore {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32#[async_trait::async_trait]
33impl CredentialStore for InMemoryStore {
34    async fn get_session_token(&self) -> Result<Option<String>> {
35        Ok(self.session.lock().unwrap().clone())
36    }
37
38    async fn set_session_token(&self, token: &str) -> Result<()> {
39        *self.session.lock().unwrap() = Some(token.to_string());
40        Ok(())
41    }
42
43    async fn delete_session_token(&self) -> Result<()> {
44        *self.session.lock().unwrap() = None;
45        Ok(())
46    }
47
48    async fn get_user_token(&self) -> Result<Option<String>> {
49        Ok(self.user.lock().unwrap().clone())
50    }
51
52    async fn set_user_token(&self, token: &str) -> Result<()> {
53        *self.user.lock().unwrap() = Some(token.to_string());
54        Ok(())
55    }
56
57    async fn delete_user_token(&self) -> Result<()> {
58        *self.user.lock().unwrap() = None;
59        Ok(())
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[tokio::test]
68    async fn test_session_token_crud() {
69        let store = InMemoryStore::new();
70        assert_eq!(store.get_session_token().await.unwrap(), None);
71
72        store.set_session_token("abc").await.unwrap();
73        assert_eq!(
74            store.get_session_token().await.unwrap(),
75            Some("abc".to_string())
76        );
77
78        store.delete_session_token().await.unwrap();
79        assert_eq!(store.get_session_token().await.unwrap(), None);
80    }
81
82    #[tokio::test]
83    async fn test_user_token_crud() {
84        let store = InMemoryStore::new();
85        assert_eq!(store.get_user_token().await.unwrap(), None);
86
87        store.set_user_token("xyz").await.unwrap();
88        assert_eq!(
89            store.get_user_token().await.unwrap(),
90            Some("xyz".to_string())
91        );
92
93        store.delete_user_token().await.unwrap();
94        assert_eq!(store.get_user_token().await.unwrap(), None);
95    }
96
97    #[tokio::test]
98    async fn test_tokens_independent() {
99        let store = InMemoryStore::new();
100
101        store.set_session_token("session").await.unwrap();
102        assert_eq!(store.get_user_token().await.unwrap(), None);
103
104        store.set_user_token("user").await.unwrap();
105        assert_eq!(
106            store.get_session_token().await.unwrap(),
107            Some("session".to_string())
108        );
109        assert_eq!(
110            store.get_user_token().await.unwrap(),
111            Some("user".to_string())
112        );
113
114        store.delete_session_token().await.unwrap();
115        assert_eq!(
116            store.get_user_token().await.unwrap(),
117            Some("user".to_string())
118        );
119    }
120
121    #[tokio::test]
122    async fn test_default() {
123        let store = InMemoryStore::default();
124        assert_eq!(store.get_session_token().await.unwrap(), None);
125        assert_eq!(store.get_user_token().await.unwrap(), None);
126    }
127}