mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 21:30:17 +08:00
2c90ae3509
Complete the device-level settings separation for cloud sync support. Backend changes: - Modify switch() to update both local settings and database is_current - Modify current() to read from local settings first, fallback to database - Rename sync_current_from_db() to sync_current_to_live() - Update tray menu to read current provider from local settings Frontend changes: - Update Settings interface: remove legacy fields (customEndpoints*, security) - Add currentProviderClaude/Codex/Gemini fields - Update settings schema accordingly Test fixes: - Update Gemini security tests to check ~/.gemini/settings.json instead of ~/.cc-switch/settings.json (security field was never stored in CC Switch settings) This ensures each device maintains its own current provider selection independently when database is synced across devices.
112 lines
3.3 KiB
Rust
112 lines
3.3 KiB
Rust
#![allow(non_snake_case)]
|
|
|
|
use serde_json::{json, Value};
|
|
use std::path::PathBuf;
|
|
use tauri::State;
|
|
use tauri_plugin_dialog::DialogExt;
|
|
|
|
use crate::error::AppError;
|
|
use crate::services::provider::ProviderService;
|
|
use crate::store::AppState;
|
|
|
|
/// 导出数据库为 SQL 备份
|
|
#[tauri::command]
|
|
pub async fn export_config_to_file(
|
|
#[allow(non_snake_case)] filePath: String,
|
|
state: State<'_, AppState>,
|
|
) -> Result<Value, String> {
|
|
let db = state.db.clone();
|
|
tauri::async_runtime::spawn_blocking(move || {
|
|
let target_path = PathBuf::from(&filePath);
|
|
db.export_sql(&target_path)?;
|
|
Ok::<_, AppError>(json!({
|
|
"success": true,
|
|
"message": "SQL exported successfully",
|
|
"filePath": filePath
|
|
}))
|
|
})
|
|
.await
|
|
.map_err(|e| format!("导出配置失败: {e}"))?
|
|
.map_err(|e: AppError| e.to_string())
|
|
}
|
|
|
|
/// 从 SQL 备份导入数据库
|
|
#[tauri::command]
|
|
pub async fn import_config_from_file(
|
|
#[allow(non_snake_case)] filePath: String,
|
|
state: State<'_, AppState>,
|
|
) -> Result<Value, String> {
|
|
let db = state.db.clone();
|
|
let db_for_state = db.clone();
|
|
tauri::async_runtime::spawn_blocking(move || {
|
|
let path_buf = PathBuf::from(&filePath);
|
|
let backup_id = db.import_sql(&path_buf)?;
|
|
|
|
// 导入后同步当前供应商到各自的 live 配置
|
|
let app_state = AppState::new(db_for_state);
|
|
if let Err(err) = ProviderService::sync_current_to_live(&app_state) {
|
|
log::warn!("导入后同步 live 配置失败: {err}");
|
|
}
|
|
|
|
// 重新加载设置到内存缓存,确保导入的设置生效
|
|
if let Err(err) = crate::settings::reload_settings() {
|
|
log::warn!("导入后重载设置失败: {err}");
|
|
}
|
|
|
|
Ok::<_, AppError>(json!({
|
|
"success": true,
|
|
"message": "SQL imported successfully",
|
|
"backupId": backup_id
|
|
}))
|
|
})
|
|
.await
|
|
.map_err(|e| format!("导入配置失败: {e}"))?
|
|
.map_err(|e: AppError| e.to_string())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn sync_current_providers_live(state: State<'_, AppState>) -> Result<Value, String> {
|
|
let db = state.db.clone();
|
|
tauri::async_runtime::spawn_blocking(move || {
|
|
let app_state = AppState::new(db);
|
|
ProviderService::sync_current_to_live(&app_state)?;
|
|
Ok::<_, AppError>(json!({
|
|
"success": true,
|
|
"message": "Live configuration synchronized"
|
|
}))
|
|
})
|
|
.await
|
|
.map_err(|e| format!("同步当前供应商失败: {e}"))?
|
|
.map_err(|e: AppError| e.to_string())
|
|
}
|
|
|
|
/// 保存文件对话框
|
|
#[tauri::command]
|
|
pub async fn save_file_dialog<R: tauri::Runtime>(
|
|
app: tauri::AppHandle<R>,
|
|
#[allow(non_snake_case)] defaultName: String,
|
|
) -> Result<Option<String>, String> {
|
|
let dialog = app.dialog();
|
|
let result = dialog
|
|
.file()
|
|
.add_filter("SQL", &["sql"])
|
|
.set_file_name(&defaultName)
|
|
.blocking_save_file();
|
|
|
|
Ok(result.map(|p| p.to_string()))
|
|
}
|
|
|
|
/// 打开文件对话框
|
|
#[tauri::command]
|
|
pub async fn open_file_dialog<R: tauri::Runtime>(
|
|
app: tauri::AppHandle<R>,
|
|
) -> Result<Option<String>, String> {
|
|
let dialog = app.dialog();
|
|
let result = dialog
|
|
.file()
|
|
.add_filter("SQL", &["sql"])
|
|
.blocking_pick_file();
|
|
|
|
Ok(result.map(|p| p.to_string()))
|
|
}
|