fix: read clash mode tolerantly and propagate mode-switch failures

The home mode card read the proxy mode only from mihomo's /configs (strict
BaseConfig); when that response drifted a single field, the whole read
failed and the card showed a bare "communication error". patch_clash_mode
also swallowed backend PATCH failures and always returned Ok, so the UI
could not tell a switch had actually failed.

- add a tolerant get_clash_mode command that reads mode from the saved
  clash config (IClashTemp::get_mode), bypassing strict BaseConfig
  deserialization, and
- make change_clash_mode return Result and have patch_clash_mode propagate
  it; the hotkey/tray callers log-and-ignore as before.
This commit is contained in:
wonfen
2026-06-27 15:30:20 +08:00
parent 1026ba88bb
commit d0d2f4e4f5
6 changed files with 59 additions and 27 deletions
+26 -21
View File
@@ -80,7 +80,10 @@ fn after_change_clash_mode() {
}
/// Change Clash mode (rule/global/direct/script)
pub async fn change_clash_mode(mode: String) {
///
/// mihomo `/configs` PATCH 失败时返回 `Err`,以便命令层把失败上抛给前端。
/// (此前该函数吞掉错误并始终视为成功,导致 UI 误判"切换成功"、看似"切不动"。)
pub async fn change_clash_mode(mode: String) -> Result<(), String> {
let mut mapping = Mapping::new();
mapping.insert(Value::from("mode"), Value::from(mode.as_str()));
// Convert YAML mapping to JSON Value
@@ -88,27 +91,29 @@ pub async fn change_clash_mode(mode: String) {
"mode": mode
});
logging!(debug, Type::Core, "change clash mode to {mode}");
match handle::Handle::mihomo().await.patch_base_config(&json_value).await {
Ok(_) => {
// 更新订阅
let clash = Config::clash().await;
clash.edit_draft(|d| d.patch_config(&mapping));
clash.apply();
// 分离数据获取和异步调用
let clash_data = clash.data_arc();
if clash_data.save_config().await.is_ok() {
handle::Handle::refresh_clash();
tray::Tray::global().update_menu_and_icon().await;
}
let is_auto_close_connection = Config::verge().await.data_arc().auto_close_connection.unwrap_or(false);
if is_auto_close_connection {
after_change_clash_mode();
}
}
Err(err) => logging!(error, Type::Core, "{err}"),
if let Err(err) = handle::Handle::mihomo().await.patch_base_config(&json_value).await {
logging!(error, Type::Core, "{err}");
return Err(err.to_string().into());
}
// 更新订阅
let clash = Config::clash().await;
clash.edit_draft(|d| d.patch_config(&mapping));
clash.apply();
// 分离数据获取和异步调用
let clash_data = clash.data_arc();
if clash_data.save_config().await.is_ok() {
handle::Handle::refresh_clash();
tray::Tray::global().update_menu_and_icon().await;
}
let is_auto_close_connection = Config::verge().await.data_arc().auto_close_connection.unwrap_or(false);
if is_auto_close_connection {
after_change_clash_mode();
}
Ok(())
}
/// Test delay to a URL through proxy.