From 5f1ba063041035761edebf4e79cce3490e503720 Mon Sep 17 00:00:00 2001 From: JSR Date: Wed, 18 Mar 2026 18:12:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=BE=E7=BD=AE=E6=9C=AA?= =?UTF-8?q?=E6=8C=81=E4=B9=85=E5=8C=96=E5=AF=BC=E8=87=B4=E9=87=8D=E5=90=AF?= =?UTF-8?q?=E5=90=8E=E9=87=8D=E5=A4=8D=E8=BF=9B=E5=85=A5OOBE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/commands/auth.rs | 20 +++++- src-tauri/src/commands/auto_score.rs | 15 +++++ src-tauri/src/commands/settings.rs | 13 +++- src-tauri/src/commands/theme.rs | 9 +++ src-tauri/src/lib.rs | 43 ++++++++----- src-tauri/src/services/settings.rs | 94 ++++++++++++++++++++++++++-- 6 files changed, 170 insertions(+), 24 deletions(-) diff --git a/src-tauri/src/commands/auth.rs b/src-tauri/src/commands/auth.rs index 2391b2e..f77ee4e 100644 --- a/src-tauri/src/commands/auth.rs +++ b/src-tauri/src/commands/auth.rs @@ -40,7 +40,10 @@ pub async fn auth_get_status( state: State<'_, Arc>>, ) -> Result, String> { let state_guard = state.read(); - let settings = state_guard.settings.read(); + let db_conn = state_guard.db.read().clone(); + let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let mut permissions = state_guard.permissions.write(); let status = AuthService::get_status(&settings, sender_id, &mut permissions); @@ -67,7 +70,10 @@ pub async fn auth_login( let result = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let security = state_guard.security.read(); let mut permissions = state_guard.permissions.write(); @@ -133,7 +139,10 @@ pub async fn auth_set_passwords( let result = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let security = state_guard.security.read(); let mut permissions = state_guard.permissions.write(); @@ -172,7 +181,10 @@ pub async fn auth_generate_recovery( let result = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let security = state_guard.security.read(); let mut permissions = state_guard.permissions.write(); @@ -205,7 +217,10 @@ pub async fn auth_reset_by_recovery( let result = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let security = state_guard.security.read(); let mut permissions = state_guard.permissions.write(); @@ -242,7 +257,10 @@ pub async fn auth_clear_all( let result = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let mut permissions = state_guard.permissions.write(); AuthService::clear_all(&mut settings, &mut permissions, sender).await diff --git a/src-tauri/src/commands/auto_score.rs b/src-tauri/src/commands/auto_score.rs index ee0d00f..4eefffc 100644 --- a/src-tauri/src/commands/auto_score.rs +++ b/src-tauri/src/commands/auto_score.rs @@ -87,8 +87,11 @@ pub async fn auto_score_add_rule( let new_id = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut auto_score_service = state_guard.auto_score.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let new_rule = AutoScoreRule { id: 0, @@ -136,8 +139,11 @@ pub async fn auto_score_update_rule( let success = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut auto_score_service = state_guard.auto_score.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let existing = auto_score_service.get_rule_by_id(rule.id); let last_executed = existing.and_then(|r| r.last_executed.clone()); @@ -191,8 +197,11 @@ pub async fn auto_score_delete_rule( let success = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut auto_score_service = state_guard.auto_score.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let success = auto_score_service.delete_rule(rule_id); @@ -233,8 +242,11 @@ pub async fn auto_score_toggle_rule( let success = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut auto_score_service = state_guard.auto_score.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; let success = auto_score_service.toggle_rule(params.rule_id, params.enabled); @@ -294,8 +306,11 @@ pub async fn auto_score_sort_rules( { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut auto_score_service = state_guard.auto_score.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; auto_score_service.sort_rules(&rule_ids); diff --git a/src-tauri/src/commands/settings.rs b/src-tauri/src/commands/settings.rs index c5c5460..a8a2b1d 100644 --- a/src-tauri/src/commands/settings.rs +++ b/src-tauri/src/commands/settings.rs @@ -74,7 +74,10 @@ pub async fn settings_get_all( state: State<'_, Arc>>, ) -> Result, String> { let state_guard = state.read(); - let settings = state_guard.settings.read(); + let db_conn = state_guard.db.read().clone(); + let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await.map_err(|e| e.to_string())?; let all = settings.get_all(); Ok(IpcResponse::success(all)) } @@ -88,7 +91,10 @@ pub async fn settings_get( SettingsKey::from_str(&key).ok_or_else(|| format!("Unknown setting key: {}", key))?; let state_guard = state.read(); - let settings = state_guard.settings.read(); + let db_conn = state_guard.db.read().clone(); + let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await.map_err(|e| e.to_string())?; let value = settings.get_value(settings_key); let json_value = settings_value_to_json(value); @@ -126,7 +132,10 @@ pub async fn settings_set( { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await.map_err(|e| e.to_string())?; settings .set_value(settings_key, settings_value) .await diff --git a/src-tauri/src/commands/theme.rs b/src-tauri/src/commands/theme.rs index 7f18d78..9b6bc02 100644 --- a/src-tauri/src/commands/theme.rs +++ b/src-tauri/src/commands/theme.rs @@ -54,8 +54,11 @@ pub async fn theme_set( let current_theme = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut theme_service = state_guard.theme.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; if theme_service.set_current_theme(&theme_id) { let _ = settings @@ -94,8 +97,11 @@ pub async fn theme_save( let current_theme = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut theme_service = state_guard.theme.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; match theme_service.save_theme(theme) { Ok(()) => { @@ -136,8 +142,11 @@ pub async fn theme_delete( let current_theme = { let state_guard = state.read(); + let db_conn = state_guard.db.read().clone(); let mut theme_service = state_guard.theme.write(); let mut settings = state_guard.settings.write(); + settings.attach_db(db_conn); + settings.initialize().await?; match theme_service.delete_theme(&theme_id) { Ok(()) => { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b3b853a..18d76fc 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -50,25 +50,34 @@ fn setup_database(app: &mut App) -> Result<(), Box> { .ok_or("Invalid database path")? .to_string(); - tauri::async_runtime::spawn(async move { - match create_sqlite_connection(&db_path_str).await { - Ok(conn) => { - if let Err(e) = run_migration(&conn, DatabaseType::SQLite).await { - eprintln!("Failed to run sqlite migration: {}", e); - return; - } - let state = handle.state::(); - let state_guard = state.write(); - let mut db_guard = state_guard.db.write(); - *db_guard = Some(conn); - eprintln!("Database connected to: {}", db_path_str); - } - Err(e) => { - eprintln!("Failed to connect to database: {}", e); - } - } + let db_result = tauri::async_runtime::block_on(async { + let conn = create_sqlite_connection(&db_path_str).await?; + run_migration(&conn, DatabaseType::SQLite).await?; + Ok::<_, Box>(conn) }); + match db_result { + Ok(conn) => { + let state = handle.state::(); + let state_guard = state.write(); + { + let mut db_guard = state_guard.db.write(); + *db_guard = Some(conn.clone()); + } + { + let mut settings = state_guard.settings.write(); + settings.attach_db(Some(conn)); + if let Err(e) = tauri::async_runtime::block_on(settings.initialize()) { + eprintln!("Failed to initialize settings from database: {}", e); + } + } + eprintln!("Database connected to: {}", db_path_str); + } + Err(e) => { + eprintln!("Failed to connect to database: {}", e); + } + } + Ok(()) } diff --git a/src-tauri/src/services/settings.rs b/src-tauri/src/services/settings.rs index 5ab8c35..5acbe87 100644 --- a/src-tauri/src/services/settings.rs +++ b/src-tauri/src/services/settings.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; +use sea_orm::{ConnectionTrait, DatabaseConnection, Statement}; use std::collections::HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -133,6 +134,8 @@ pub enum PermissionRequirement { pub struct SettingsService { cache: HashMap, initialized: bool, + db_loaded: bool, + db_conn: Option, } impl Default for SettingsService { @@ -146,19 +149,88 @@ impl SettingsService { Self { cache: HashMap::new(), initialized: false, + db_loaded: false, + db_conn: None, + } + } + + pub fn attach_db(&mut self, conn: Option) { + if conn.is_some() { + self.db_conn = conn; } } pub async fn initialize(&mut self) -> Result<(), String> { - if self.initialized { + if self.initialized && (self.db_loaded || self.db_conn.is_none()) { return Ok(()); } - self.ensure_defaults(); + if let Some(conn) = self.db_conn.clone() { + if !self.db_loaded { + self.load_cache_from_db(&conn).await?; + self.ensure_defaults_in_db(&conn).await?; + self.db_loaded = true; + } + } else { + self.ensure_defaults(); + } self.initialized = true; Ok(()) } + fn escape_sql(value: &str) -> String { + value.replace('\'', "''") + } + + async fn load_cache_from_db(&mut self, conn: &DatabaseConnection) -> Result<(), String> { + let sql = "SELECT key, value FROM settings".to_string(); + let rows = conn + .query_all(Statement::from_string(conn.get_database_backend(), sql)) + .await + .map_err(|e| e.to_string())?; + + self.cache.clear(); + for row in rows { + let key: String = row.try_get("", "key").map_err(|e| e.to_string())?; + let value: String = row.try_get("", "value").map_err(|e| e.to_string())?; + self.cache.insert(key, value); + } + + Ok(()) + } + + async fn upsert_raw_db( + &self, + conn: &DatabaseConnection, + key: &str, + value: &str, + ) -> Result<(), String> { + let key_escaped = Self::escape_sql(key); + let value_escaped = Self::escape_sql(value); + let sql = format!( + "INSERT INTO settings (key, value) VALUES ('{}', '{}') ON CONFLICT(key) DO UPDATE SET value = EXCLUDED.value", + key_escaped, value_escaped + ); + + conn.execute(Statement::from_string(conn.get_database_backend(), sql)) + .await + .map_err(|e| e.to_string())?; + Ok(()) + } + + async fn ensure_defaults_in_db(&mut self, conn: &DatabaseConnection) -> Result<(), String> { + let definitions = Self::get_definitions(); + for (key, def) in definitions.iter() { + let key_str = key.as_str(); + if !self.cache.contains_key(key_str) { + let raw = def.default_value.to_raw(); + self.upsert_raw_db(conn, key_str, &raw).await?; + self.cache.insert(key_str.to_string(), raw); + } + } + Ok(()) + } + pub fn get_definitions() -> HashMap { let mut defs = HashMap::new(); @@ -279,6 +351,8 @@ impl SettingsService { } pub async fn set_raw(&mut self, key: &str, value: &str) -> Result<(), String> { + self.initialize().await?; + if let Some(settings_key) = SettingsKey::from_str(key) { let definitions = Self::get_definitions(); if let Some(def) = definitions.get(&settings_key) { @@ -292,11 +366,17 @@ impl SettingsService { } else { parsed.to_raw() }; - self.cache.insert(key.to_string(), validated); + self.cache.insert(key.to_string(), validated.clone()); + if let Some(conn) = self.db_conn.clone() { + self.upsert_raw_db(&conn, key, &validated).await?; + } return Ok(()); } } self.cache.insert(key.to_string(), value.to_string()); + if let Some(conn) = self.db_conn.clone() { + self.upsert_raw_db(&conn, key, value).await?; + } Ok(()) } @@ -322,6 +402,8 @@ impl SettingsService { key: SettingsKey, value: SettingsValue, ) -> Result<(), String> { + self.initialize().await?; + let definitions = Self::get_definitions(); if let Some(def) = definitions.get(&key) { if let Some(validate_fn) = def.validate { @@ -329,7 +411,11 @@ impl SettingsService { return Err(format!("Invalid value for setting: {:?}", key)); } } - self.cache.insert(key.as_str().to_string(), value.to_raw()); + let raw = value.to_raw(); + self.cache.insert(key.as_str().to_string(), raw.clone()); + if let Some(conn) = self.db_conn.clone() { + self.upsert_raw_db(&conn, key.as_str(), &raw).await?; + } } Ok(()) }