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