mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-18 15:21:05 +08:00
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:
@@ -36,10 +36,21 @@ pub async fn patch_clash_config(payload: Mapping) -> CmdResult {
|
||||
}
|
||||
|
||||
/// 修改Clash模式
|
||||
///
|
||||
/// 将 `change_clash_mode` 的失败上抛给前端,使前端 `catch` 能真正感知后端 PATCH 失败
|
||||
/// 并提示用户(此前命令始终返回 `Ok(())`,吞掉了后端错误)。
|
||||
#[tauri::command]
|
||||
pub async fn patch_clash_mode(payload: String) -> CmdResult {
|
||||
feat::change_clash_mode(payload).await;
|
||||
Ok(())
|
||||
feat::change_clash_mode(payload).await
|
||||
}
|
||||
|
||||
/// 获取当前 Clash 模式(容错读取)
|
||||
///
|
||||
/// 直接读取已保存的 clash 配置中的 `mode`,绕开 mihomo `/configs` 的严格
|
||||
/// `BaseConfig` 反序列化,作为主页 mode 显示的兜底来源。
|
||||
#[tauri::command]
|
||||
pub async fn get_clash_mode() -> CmdResult<Option<String>> {
|
||||
Ok(Config::clash().await.data_arc().get_mode().map(Into::into))
|
||||
}
|
||||
|
||||
/// 切换Clash核心
|
||||
|
||||
@@ -180,6 +180,17 @@ impl IClashTemp {
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// 容错读取当前代理模式。
|
||||
///
|
||||
/// 仅从已保存的 clash 配置 Mapping 中提取 `mode` 字段,不依赖 mihomo `/configs`
|
||||
/// 的严格 `BaseConfig` 反序列化,因此即使核心返回的字段与插件结构体不匹配也能取到。
|
||||
pub fn get_mode(&self) -> Option<String> {
|
||||
self.0.get("mode").and_then(|value| match value {
|
||||
Value::String(val_str) => Some(val_str.clone()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn guard_redir_port(config: &Mapping) -> u16 {
|
||||
let mut port = config
|
||||
|
||||
@@ -125,19 +125,22 @@ impl Hotkey {
|
||||
}
|
||||
HotkeyFunction::ClashModeRule => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::change_clash_mode("rule".into()).await;
|
||||
// 错误已在 change_clash_mode 内部记录,此处显式忽略返回值
|
||||
let _ = feat::change_clash_mode("rule".into()).await;
|
||||
notify_event(NotificationEvent::ClashModeChanged { mode: "Rule" }).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::ClashModeGlobal => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::change_clash_mode("global".into()).await;
|
||||
// 错误已在 change_clash_mode 内部记录,此处显式忽略返回值
|
||||
let _ = feat::change_clash_mode("global".into()).await;
|
||||
notify_event(NotificationEvent::ClashModeChanged { mode: "Global" }).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::ClashModeDirect => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::change_clash_mode("direct".into()).await;
|
||||
// 错误已在 change_clash_mode 内部记录,此处显式忽略返回值
|
||||
let _ = feat::change_clash_mode("direct".into()).await;
|
||||
notify_event(NotificationEvent::ClashModeChanged { mode: "Direct" }).await;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -933,7 +933,8 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
||||
&& let Some(final_mode) = stripped.strip_suffix("_mode")
|
||||
{
|
||||
logging!(info, Type::ProxyMode, "Switch Proxy Mode To: {}", final_mode);
|
||||
feat::change_clash_mode(final_mode.into()).await;
|
||||
// 错误已在 change_clash_mode 内部记录,此处显式忽略返回值
|
||||
let _ = feat::change_clash_mode(final_mode.into()).await;
|
||||
}
|
||||
}
|
||||
MenuIds::DASHBOARD => {
|
||||
|
||||
+26
-21
@@ -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.
|
||||
|
||||
@@ -160,6 +160,7 @@ mod app_init {
|
||||
cmd::get_clash_info,
|
||||
cmd::patch_clash_config,
|
||||
cmd::patch_clash_mode,
|
||||
cmd::get_clash_mode,
|
||||
cmd::change_clash_core,
|
||||
cmd::get_runtime_config,
|
||||
cmd::get_runtime_yaml,
|
||||
|
||||
Reference in New Issue
Block a user