soothe_client/appkit/
session_store.rs1use std::collections::HashMap;
4use std::sync::Arc;
5
6use serde_json::Value;
7use tokio::sync::Mutex;
8
9#[derive(Debug, Clone, Default)]
11pub struct SessionRecord {
12 pub session_id: String,
14 pub loop_id: Option<String>,
16 pub workspace_id: String,
18 pub user_id: String,
20 pub reset_count: u32,
22 pub messages: Vec<Value>,
24}
25
26pub trait SessionStore: Send + Sync {
28 fn get_session(
30 &self,
31 session_id: &str,
32 ) -> impl std::future::Future<Output = Option<SessionRecord>> + Send;
33
34 fn create_session(
36 &self,
37 record: SessionRecord,
38 ) -> impl std::future::Future<Output = SessionRecord> + Send;
39
40 fn update_last_used(&self, session_id: &str) -> impl std::future::Future<Output = ()> + Send;
42
43 fn increment_reset_count(
45 &self,
46 session_id: &str,
47 ) -> impl std::future::Future<Output = ()> + Send;
48
49 fn get_loop_id_for_session(
51 &self,
52 session_id: &str,
53 ) -> impl std::future::Future<Output = Option<String>> + Send;
54
55 fn set_loop_id(
57 &self,
58 session_id: &str,
59 loop_id: &str,
60 ) -> impl std::future::Future<Output = ()> + Send;
61
62 fn append_message(
64 &self,
65 session_id: &str,
66 message: Value,
67 ) -> impl std::future::Future<Output = ()> + Send;
68}
69
70#[derive(Clone, Default)]
72pub struct InMemorySessionStore {
73 inner: Arc<Mutex<HashMap<String, SessionRecord>>>,
74}
75
76impl InMemorySessionStore {
77 pub fn new() -> Self {
79 Self::default()
80 }
81}
82
83impl SessionStore for InMemorySessionStore {
84 async fn get_session(&self, session_id: &str) -> Option<SessionRecord> {
85 self.inner.lock().await.get(session_id).cloned()
86 }
87
88 async fn create_session(&self, record: SessionRecord) -> SessionRecord {
89 let mut map = self.inner.lock().await;
90 map.insert(record.session_id.clone(), record.clone());
91 record
92 }
93
94 async fn update_last_used(&self, _session_id: &str) {}
95
96 async fn increment_reset_count(&self, session_id: &str) {
97 if let Some(rec) = self.inner.lock().await.get_mut(session_id) {
98 rec.reset_count += 1;
99 }
100 }
101
102 async fn get_loop_id_for_session(&self, session_id: &str) -> Option<String> {
103 self.inner
104 .lock()
105 .await
106 .get(session_id)
107 .and_then(|r| r.loop_id.clone())
108 }
109
110 async fn set_loop_id(&self, session_id: &str, loop_id: &str) {
111 let mut map = self.inner.lock().await;
112 if let Some(rec) = map.get_mut(session_id) {
113 rec.loop_id = Some(loop_id.to_string());
114 } else {
115 map.insert(
116 session_id.to_string(),
117 SessionRecord {
118 session_id: session_id.to_string(),
119 loop_id: Some(loop_id.to_string()),
120 ..Default::default()
121 },
122 );
123 }
124 }
125
126 async fn append_message(&self, session_id: &str, message: Value) {
127 if let Some(rec) = self.inner.lock().await.get_mut(session_id) {
128 rec.messages.push(message);
129 }
130 }
131}