Skip to main content

rustbasic_cli/
database.rs

1use std::fs;
2use rustbasic_core::Config;
3use rustbasic_core::database::connect;
4use base64::{Engine as _, engine::general_purpose};
5use rand::Rng;
6use regex::Regex;
7use colored::*;
8use sea_orm::ConnectionTrait;
9
10pub async fn clear_cache() {
11    println!("\n{}", "๐Ÿงน Cleaning Cache & Logs...".magenta().bold());
12
13    // 1. Clear Logs
14    let log_dir = "storage/logs";
15    if let Ok(entries) = fs::read_dir(log_dir) {
16        let mut count = 0;
17        for entry in entries.flatten() {
18            let path = entry.path();
19            if path.is_file() {
20                let _ = fs::OpenOptions::new()
21                    .write(true)
22                    .truncate(true)
23                    .open(&path);
24                count += 1;
25            }
26        }
27        println!("   {} Folder storage/logs telah dikosongkan. ({} file dibersihkan)", "โœ… Logs:".green(), count);
28    } else {
29        println!("   {} Folder storage/logs tidak ditemukan.", "โš ๏ธ  Logs:".yellow());
30    }
31
32    // 2. Clear Sessions in DB
33    let cfg = Config::load();
34    let db = connect(&cfg).await;
35    
36    let truncate_sql = if cfg.db_connection == "mysql" {
37        "TRUNCATE TABLE sessions"
38    } else {
39        "DELETE FROM sessions"
40    };
41
42    match db.execute(sea_orm::Statement::from_string(cfg.db_backend(), truncate_sql.to_string())).await {
43        Ok(_) => println!("   {} Tabel sessions telah dikosongkan.", "โœ… Sessions:".green()),
44        Err(e) => println!("   {} Gagal membersihkan tabel sessions. ({})", "โŒ Error:".red(), e),
45    }
46
47    println!("\n{}", "โœจ Cache berhasil dibersihkan!".green().bold());
48}
49
50pub fn generate_app_key() {
51    println!("\n{}", "๐Ÿ”‘ Generating Application Key...".magenta().bold());
52
53    let mut key = [0u8; 32];
54    rand::rng().fill_bytes(&mut key);
55    
56    let encoded = general_purpose::STANDARD.encode(key);
57    let key_str = format!("base64:{}", encoded);
58    
59    let env_path = ".env";
60    match fs::read_to_string(env_path) {
61        Ok(content) => {
62            let re = Regex::new(r"(?m)^APP_KEY=.*").unwrap();
63            let new_content = if re.is_match(&content) {
64                re.replace(&content, &format!("APP_KEY={}", key_str)).to_string()
65            } else {
66                format!("{}\nAPP_KEY={}", content.trim_end(), key_str)
67            };
68
69            if let Err(e) = fs::write(env_path, new_content) {
70                println!("{} Gagal menulis ke file .env: {}", "โŒ Error:".red(), e);
71            } else {
72                println!("{} {}", "โœ… Application key set successfully:".green(), key_str.cyan());
73                println!("{}", "๐Ÿ’ก Pastikan untuk tidak membagikan APP_KEY ini ke publik!".dimmed());
74            }
75        }
76        Err(_) => {
77            println!("{} File .env tidak ditemukan.", "โŒ Error:".red());
78        }
79    }
80}
81
82pub async fn ensure_session() {
83    if !std::path::Path::new(".env").exists() {
84        return;
85    }
86
87    let _ = dotenvy::dotenv();
88    let cfg = Config::load();
89
90    // 1. Hubungkan ke database dengan aman (tanpa panik jika gagal)
91    let db_url = if cfg.db_connection == "mysql" {
92        format!(
93            "mysql://{}:{}@{}:{}/{}",
94            cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port, cfg.db_database
95        )
96    } else {
97        format!("sqlite:database/{}.sqlite?mode=rwc", cfg.db_database)
98    };
99
100    // Pastikan folder database ada untuk sqlite
101    if cfg.db_connection != "mysql" {
102        let _ = std::fs::create_dir_all("database");
103    }
104
105    let mut opt = sea_orm::ConnectOptions::new(db_url);
106    opt.max_connections(5)
107       .connect_timeout(std::time::Duration::from_secs(3))
108       .sqlx_logging(false);
109
110    let db = match sea_orm::Database::connect(opt).await {
111        Ok(conn) => conn,
112        Err(_) => {
113            // Abaikan jika database belum siap/tidak bisa terhubung (agar perintah seperti migrate/help/new tidak crash)
114            return;
115        }
116    };
117
118    // 2. Pastikan tabel sessions ada di database
119    let create_table_sql = if cfg.db_connection == "mysql" {
120        "CREATE TABLE IF NOT EXISTS sessions (
121            id VARCHAR(255) PRIMARY KEY,
122            payload TEXT NOT NULL,
123            last_activity BIGINT NOT NULL,
124            ip_address VARCHAR(45)
125        )"
126    } else {
127        "CREATE TABLE IF NOT EXISTS sessions (
128            id TEXT PRIMARY KEY,
129            payload TEXT NOT NULL,
130            last_activity BIGINT NOT NULL,
131            ip_address TEXT
132        )"
133    };
134
135    let stmt = sea_orm::Statement::from_string(db.get_database_backend(), create_table_sql.to_string());
136    if db.execute(stmt).await.is_err() {
137        return;
138    }
139
140    // 3. Baca dan verifikasi session ID
141    let session_file = ".rustbasic_session";
142    let mut session_id = String::new();
143    let mut need_to_write = false;
144
145    if let Ok(content) = fs::read_to_string(session_file) {
146        session_id = content.trim().to_string();
147    }
148
149    let mut session_exists = false;
150
151    if !session_id.is_empty() {
152        let check_sql = format!("SELECT id FROM sessions WHERE id = '{}'", session_id);
153        let stmt = sea_orm::Statement::from_string(db.get_database_backend(), check_sql);
154        if let Ok(Some(_)) = db.query_one(stmt).await {
155            session_exists = true;
156        }
157    }
158
159    if !session_exists {
160        let mut bytes = [0u8; 32];
161        rand::rng().fill_bytes(&mut bytes);
162        session_id = general_purpose::STANDARD.encode(bytes);
163        need_to_write = true;
164
165        let now = chrono::Utc::now().timestamp();
166        let insert_sql = format!(
167            "INSERT INTO sessions (id, payload, last_activity, ip_address) VALUES ('{}', '{}', {}, '{}')",
168            session_id, "{}", now, "127.0.0.1"
169        );
170        let stmt = sea_orm::Statement::from_string(db.get_database_backend(), insert_sql);
171        if db.execute(stmt).await.is_ok() {
172            println!("โœจ {} ({})", "Session baru berhasil dibuat dan disimpan di database.".green().bold(), session_id.cyan());
173        }
174    } else {
175        let now = chrono::Utc::now().timestamp();
176        let update_sql = format!(
177            "UPDATE sessions SET last_activity = {} WHERE id = '{}'",
178            now, session_id
179        );
180        let stmt = sea_orm::Statement::from_string(db.get_database_backend(), update_sql);
181        let _ = db.execute(stmt).await;
182    }
183
184    if need_to_write {
185        let _ = fs::write(session_file, &session_id);
186    }
187}
188