mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 16:56:16 +08:00
fix: prevent common config loss during proxy takeover and stabilize snippet lifecycle
- Make sync_current_provider_for_app takeover-aware: update restore backup instead of overwriting live config when proxy is active - Introduce explicit "cleared" flag for common config snippets to prevent auto-extraction from resurrecting user-cleared snippets - Reorder startup: extract snippets from clean live files before restoring proxy takeover state - Add one-time migration flag to skip legacy commonConfigEnabled migration on subsequent startups - Add regression tests for takeover backup preservation, explicit clear semantics, and migration flag roundtrip
This commit is contained in:
@@ -212,20 +212,22 @@ pub async fn set_claude_common_config_snippet(
|
||||
snippet: String,
|
||||
state: tauri::State<'_, crate::store::AppState>,
|
||||
) -> Result<(), String> {
|
||||
let is_cleared = snippet.trim().is_empty();
|
||||
|
||||
if !snippet.trim().is_empty() {
|
||||
serde_json::from_str::<serde_json::Value>(&snippet).map_err(invalid_json_format_error)?;
|
||||
}
|
||||
|
||||
let value = if snippet.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(snippet)
|
||||
};
|
||||
let value = if is_cleared { None } else { Some(snippet) };
|
||||
|
||||
state
|
||||
.db
|
||||
.set_config_snippet("claude", value)
|
||||
.map_err(|e| e.to_string())?;
|
||||
state
|
||||
.db
|
||||
.set_config_snippet_cleared("claude", is_cleared)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -246,6 +248,7 @@ pub async fn set_common_config_snippet(
|
||||
snippet: String,
|
||||
state: tauri::State<'_, crate::store::AppState>,
|
||||
) -> Result<(), String> {
|
||||
let is_cleared = snippet.trim().is_empty();
|
||||
let old_snippet = state
|
||||
.db
|
||||
.get_config_snippet(&app_type)
|
||||
@@ -253,11 +256,7 @@ pub async fn set_common_config_snippet(
|
||||
|
||||
validate_common_config_snippet(&app_type, &snippet)?;
|
||||
|
||||
let value = if snippet.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(snippet)
|
||||
};
|
||||
let value = if is_cleared { None } else { Some(snippet) };
|
||||
|
||||
if matches!(app_type.as_str(), "claude" | "codex" | "gemini") {
|
||||
if let Some(legacy_snippet) = old_snippet
|
||||
@@ -278,6 +277,10 @@ pub async fn set_common_config_snippet(
|
||||
.db
|
||||
.set_config_snippet(&app_type, value)
|
||||
.map_err(|e| e.to_string())?;
|
||||
state
|
||||
.db
|
||||
.set_config_snippet_cleared(&app_type, is_cleared)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
if matches!(app_type.as_str(), "claude" | "codex" | "gemini") {
|
||||
let app = AppType::from_str(&app_type).map_err(|e| e.to_string())?;
|
||||
|
||||
@@ -103,16 +103,16 @@ fn import_default_config_internal(state: &AppState, app_type: AppType) -> Result
|
||||
// Extract common config snippet (mirrors old startup logic in lib.rs)
|
||||
if state
|
||||
.db
|
||||
.get_config_snippet(app_type.as_str())
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_none()
|
||||
.should_auto_extract_config_snippet(app_type.as_str())?
|
||||
{
|
||||
match ProviderService::extract_common_config_snippet(state, app_type.clone()) {
|
||||
Ok(snippet) if !snippet.is_empty() && snippet != "{}" => {
|
||||
let _ = state
|
||||
.db
|
||||
.set_config_snippet(app_type.as_str(), Some(snippet));
|
||||
let _ = state
|
||||
.db
|
||||
.set_config_snippet_cleared(app_type.as_str(), false);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user