Skip to main content

rustbasic_core/
session.rs

1use crate::Config;
2use crate::session_manager::RustBasicSessionStore;
3use sqlx::AnyPool;
4use std::sync::Arc;
5use std::sync::Mutex;
6use serde_json::Value;
7
8#[derive(Clone)]
9pub struct Session {
10    pub(crate) id: String,
11    pub(crate) data: Arc<Mutex<serde_json::Map<String, Value>>>,
12}
13
14impl Session {
15    pub fn new(id: String) -> Self {
16        Self {
17            id,
18            data: Arc::new(Mutex::new(serde_json::Map::new())),
19        }
20    }
21
22    pub fn get<T: serde::de::DeserializeOwned>(&self, key: &str) -> Option<T> {
23        let guard = self.data.lock().unwrap();
24        let val = guard.get(key)?;
25        serde_json::from_value(val.clone()).ok()
26    }
27
28    pub fn set<T: serde::Serialize>(&self, key: &str, value: T) {
29        if let Ok(val) = serde_json::to_value(value) {
30            self.data.lock().unwrap().insert(key.to_string(), val);
31        }
32    }
33
34    pub fn remove(&self, key: &str) -> Option<Value> {
35        self.data.lock().unwrap().remove(key)
36    }
37
38    pub fn id(&self) -> &str {
39        &self.id
40    }
41}
42
43pub async fn setup_session(cfg: &Config) -> RustBasicSessionStore {
44    let session_db_url = if cfg.session_driver == "file" {
45        "sqlite:database/sessions.sqlite?mode=rwc".to_string()
46    } else if cfg.db_connection == "mysql" {
47        format!(
48            "mysql://{}:{}@{}:{}/{}",
49            cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port, cfg.db_database
50        )
51    } else {
52        format!("sqlite:database/{}.sqlite?mode=rwc", cfg.db_database)
53    };
54
55    sqlx::any::install_default_drivers();
56    let session_pool = match AnyPool::connect(&session_db_url).await {
57        Ok(pool) => pool,
58        Err(e) => {
59            let err_msg = e.to_string();
60            if (err_msg.contains("1049") || err_msg.contains("Unknown database")) && cfg.db_connection == "mysql" {
61                let root_url = format!("mysql://{}:{}@{}:{}", cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port);
62                if let Ok(root_pool) = sqlx::MySqlPool::connect(&root_url).await {
63                    let _ = sqlx::query(&format!("CREATE DATABASE IF NOT EXISTS `{}`", cfg.db_database)).execute(&root_pool).await;
64                    AnyPool::connect(&session_db_url).await.expect("Gagal terhubung setelah membuat DB session")
65                } else {
66                    panic!("Gagal membuat database session otomatis: {:?}", e);
67                }
68            } else {
69                panic!("Gagal terhubung ke database session: {:?}", e);
70            }
71        }
72    };
73    
74    RustBasicSessionStore::new(session_pool)
75}
76
77pub async fn init_sessions(cfg: &Config) {
78    let db_url = if cfg.session_driver == "file" {
79        "sqlite:database/sessions.sqlite?mode=rwc".to_string()
80    } else if cfg.db_connection == "mysql" {
81        format!(
82            "mysql://{}:{}@{}:{}/{}",
83            cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port, cfg.db_database
84        )
85    } else {
86        format!("sqlite:database/{}.sqlite?mode=rwc", cfg.db_database)
87    };
88
89    sqlx::any::install_default_drivers();
90    let pool = AnyPool::connect(&db_url).await.expect("Gagal terhubung ke database session");
91
92    let sql = if cfg.db_connection == "mysql" {
93        "CREATE TABLE IF NOT EXISTS sessions (
94            id VARCHAR(255) PRIMARY KEY,
95            payload VARCHAR(8000) NOT NULL,
96            last_activity BIGINT NOT NULL,
97            ip_address VARCHAR(45)
98        )"
99    } else {
100        "CREATE TABLE IF NOT EXISTS sessions (
101            id VARCHAR(255) PRIMARY KEY,
102            payload TEXT NOT NULL,
103            last_activity BIGINT NOT NULL,
104            ip_address VARCHAR(45)
105        )"
106    };
107
108    sqlx::query(sql).execute(&pool).await.expect("Gagal membuat tabel session otomatis");
109}