修复设置未持久化导致重启后重复进入OOBE

This commit is contained in:
JSR
2026-03-18 18:12:23 +08:00
parent 21fa361e49
commit 5f1ba06304
6 changed files with 170 additions and 24 deletions
+19 -1
View File
@@ -40,7 +40,10 @@ pub async fn auth_get_status(
state: State<'_, Arc<RwLock<AppState>>>,
) -> Result<IpcResponse<AuthStatusResponse>, 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
+15
View File
@@ -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);
+11 -2
View File
@@ -74,7 +74,10 @@ pub async fn settings_get_all(
state: State<'_, Arc<RwLock<AppState>>>,
) -> Result<IpcResponse<SettingsSpec>, 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
+9
View File
@@ -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(()) => {
+26 -17
View File
@@ -50,25 +50,34 @@ fn setup_database(app: &mut App) -> Result<(), Box<dyn std::error::Error>> {
.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::<crate::state::SafeAppState>();
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<dyn std::error::Error>>(conn)
});
match db_result {
Ok(conn) => {
let state = handle.state::<crate::state::SafeAppState>();
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(())
}
+90 -4
View File
@@ -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<String, String>,
initialized: bool,
db_loaded: bool,
db_conn: Option<DatabaseConnection>,
}
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<DatabaseConnection>) {
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<SettingsKey, SettingDefinition> {
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(())
}