rustbasic_core/
session_manager.rs1use crate::sql::AnyPool;
2
3fn replace_postgres_placeholders(sql: &str) -> String {
6 let mut result = String::with_capacity(sql.len());
7 let mut chars = sql.chars().peekable();
8
9 while let Some(ch) = chars.next() {
10 if ch == '$' {
11 let has_digit = chars.peek().map_or(false, |c| c.is_ascii_digit());
13 if has_digit {
14 while chars.peek().map_or(false, |c| c.is_ascii_digit()) {
15 chars.next();
16 }
17 result.push('?');
18 } else {
19 result.push('$');
20 }
21 } else {
22 result.push(ch);
23 }
24 }
25
26 result
27}
28
29#[derive(Clone, Debug)]
30pub struct RustBasicSessionStore {
31 pub pool: AnyPool,
32}
33
34impl RustBasicSessionStore {
35 pub fn new(pool: AnyPool) -> Self {
36 Self { pool }
37 }
38
39 async fn get_placeholder_query(&self, sql: &str) -> String {
40 let is_mysql = if let Ok(conn) = self.pool.acquire().await {
41 conn.backend_name() == "MySQL"
42 } else {
43 false
44 };
45
46 if is_mysql {
47 replace_postgres_placeholders(sql)
48 } else {
49 sql.to_string()
50 }
51 }
52
53 pub async fn load(&self, id: &str) -> Option<String> {
54 let raw_query = "SELECT payload FROM sessions WHERE id = $1 AND last_activity > $2";
55 let query = self.get_placeholder_query(raw_query).await;
56 let now = crate::chrono::Utc::now().timestamp();
57
58 let row_opt = crate::sql::query(&query)
59 .bind(id)
60 .bind(now)
61 .fetch_optional(&self.pool)
62 .await
63 .ok()
64 .flatten();
65
66 if let Some(row) = row_opt {
67 if let Ok(s) = row.try_get::<String, _>(0) {
68 return Some(s);
69 }
70 if let Ok(bytes) = row.try_get::<Vec<u8>, _>(0) {
71 if let Ok(s) = String::from_utf8(bytes) {
72 return Some(s);
73 }
74 }
75 }
76 None
77 }
78
79 pub async fn store(&self, id: &str, session_json: &str, ip: &str) {
80 let raw_delete_query = "DELETE FROM sessions WHERE id = $1";
81 let delete_query = self.get_placeholder_query(raw_delete_query).await;
82 let _ = crate::sql::query(&delete_query).bind(id).execute(&self.pool).await;
83
84 let raw_insert_query = "INSERT INTO sessions (id, payload, last_activity, ip_address) VALUES ($1, $2, $3, $4)";
85 let insert_query = self.get_placeholder_query(raw_insert_query).await;
86 let expires = crate::chrono::Utc::now().timestamp() + 14 * 24 * 60 * 60; let _ = crate::sql::query(&insert_query)
89 .bind(id)
90 .bind(session_json)
91 .bind(expires)
92 .bind(ip)
93 .execute(&self.pool)
94 .await;
95 }
96}