rustbasic_core/
session.rs1use crate::Config;
2use crate::session_manager::RustBasicSessionStore;
3use crate::sql::{self, 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 sql::any::install_default_drivers();
56 let session_pool = match AnyPool::connect(&session_db_url).await {
57 Ok(pool) => pool,
58 Err(e) => {
59 #[cfg(feature = "mysql")]
60 {
61 let err_msg = e.to_string();
62 if (err_msg.contains("1049") || err_msg.contains("Unknown database")) && cfg.db_connection == "mysql" {
63 let root_url = format!("mysql://{}:{}@{}:{}", cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port);
64 if let Ok(root_pool) = sql::MySqlPool::connect(&root_url).await {
65 let _ = sql::query(&format!("CREATE DATABASE IF NOT EXISTS `{}`", cfg.db_database)).execute(&root_pool).await;
66 AnyPool::connect(&session_db_url).await.expect("Gagal terhubung setelah membuat DB session")
67 } else {
68 panic!("Gagal membuat database session otomatis: {:?}", e);
69 }
70 } else {
71 panic!("Gagal terhubung ke database session: {:?}", e);
72 }
73 }
74 #[cfg(not(feature = "mysql"))]
75 panic!("Gagal terhubung ke database session: {:?}", e);
76 }
77 };
78
79 RustBasicSessionStore::new(session_pool)
80}
81
82pub async fn init_sessions(cfg: &Config) {
83 let db_url = if cfg.session_driver == "file" {
84 "sqlite:database/sessions.sqlite?mode=rwc".to_string()
85 } else if cfg.db_connection == "mysql" {
86 format!(
87 "mysql://{}:{}@{}:{}/{}",
88 cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port, cfg.db_database
89 )
90 } else {
91 format!("sqlite:database/{}.sqlite?mode=rwc", cfg.db_database)
92 };
93
94 sql::any::install_default_drivers();
95 let pool = AnyPool::connect(&db_url).await.expect("Gagal terhubung ke database session");
96
97 let sql = if cfg.db_connection == "mysql" {
98 "CREATE TABLE IF NOT EXISTS sessions (
99 id VARCHAR(255) PRIMARY KEY,
100 payload VARCHAR(8000) NOT NULL,
101 last_activity BIGINT NOT NULL,
102 ip_address VARCHAR(45)
103 )"
104 } else {
105 "CREATE TABLE IF NOT EXISTS sessions (
106 id VARCHAR(255) PRIMARY KEY,
107 payload TEXT NOT NULL,
108 last_activity BIGINT NOT NULL,
109 ip_address VARCHAR(45)
110 )"
111 };
112
113 sql::query(sql).execute(&pool).await.expect("Gagal membuat tabel session otomatis");
114}