Files
clash-verge-rev/src-tauri/src/feat/clash.rs
oomeow 7fc238c27b refactor: invock mihomo api by use tauri-plugin-mihomo (#4926)
* feat: add tauri-plugin-mihomo

* refactor: invock mihomo api by use tauri-plugin-mihomo

* chore: todo

* chore: update

* chore: update

* chore: update

* chore: update

* fix: incorrect delay status and update pretty config

* chore: update

* chore: remove cache

* chore: update

* chore: update

* fix: app freezed when change group proxy

* chore: update

* chore: update

* chore: add rustfmt.toml to tauri-plugin-mihomo

* chore: happy clippy

* refactor: connect mihomo websocket

* chore: update

* chore: update

* fix: parse bigint to number

* chore: update

* Revert "fix: parse bigint to number"

This reverts commit 74c006522e.

* chore: use number instead of bigint

* chore: cleanup

* fix: rule data not refresh when switch profile

* chore: update

* chore: cleanup

* chore: update

* fix: traffic graph data display

* feat: add ipc connection pool

* chore: update

* chore: clippy

* fix: incorrect delay status

* fix: typo

* fix: empty proxies tray menu

* chore: clippy

* chore: import tauri-plugin-mihomo by using git repo

* chore: cleanup

* fix: mihomo api

* fix: incorrect delay status

* chore: update tauri-plugin-mihomo dep

chore: update
2025-10-08 12:32:40 +08:00

176 lines
5.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use crate::{
config::Config,
core::{CoreManager, handle, tray},
logging_error,
process::AsyncHandler,
utils::{logging::Type, resolve},
};
use serde_yaml_ng::{Mapping, Value};
/// Restart the Clash core
pub async fn restart_clash_core() {
match CoreManager::global().restart_core().await {
Ok(_) => {
handle::Handle::refresh_clash();
handle::Handle::notice_message("set_config::ok", "ok");
}
Err(err) => {
handle::Handle::notice_message("set_config::error", format!("{err}"));
log::error!(target:"app", "{err}");
}
}
}
/// Restart the application
pub async fn restart_app() {
if let Err(err) = resolve::resolve_reset_async().await {
handle::Handle::notice_message(
"restart_app::error",
format!("Failed to cleanup resources: {err}"),
);
log::error!(target:"app", "Restart failed during cleanup: {err}");
return;
}
let app_handle = handle::Handle::app_handle();
app_handle.restart();
// TODO: PR Ref: https://github.com/clash-verge-rev/clash-verge-rev/pull/4960
// handle::Handle::notice_message("restart_app::info", "Restarting application...");
// // Use the manual restart method consistently to ensure reliability across platforms
// // This addresses the issue where app_handle.restart() doesn't work properly on Windows
// let current_exe = match env::current_exe() {
// Ok(path) => path,
// Err(_) => {
// // If we can't get the current executable path, try to use the fallback method
// if let Some(app_handle) = handle::Handle::global().app_handle() {
// app_handle.restart();
// }
// exit(1); // If we reach here, either app_handle was None or restart() failed to restart
// }
// };
// let mut cmd = Command::new(current_exe);
// cmd.args(env::args().skip(1));
// match cmd.spawn() {
// Ok(child) => {
// log::info!(target: "app", "New application instance started with PID: {}", child.id());
// // Successfully started new process, now exit current process
// if let Some(app_handle) = handle::Handle::global().app_handle() {
// app_handle.exit(0);
// } else {
// exit(0);
// }
// }
// Err(e) => {
// log::error!(target: "app", "Failed to start new application instance: {}", e);
// // If manual spawn fails, try the original restart method as a last resort
// if let Some(app_handle) = handle::Handle::global().app_handle() {
// app_handle.restart();
// } else {
// exit(1);
// }
// }
// }
}
fn after_change_clash_mode() {
AsyncHandler::spawn(move || async {
let mihomo = handle::Handle::mihomo().await;
match mihomo.get_connections().await {
Ok(connections) => {
if let Some(connections_array) = connections.connections {
for connection in connections_array {
let _ = mihomo.close_connection(&connection.id).await;
}
}
}
Err(err) => {
log::error!(target: "app", "Failed to get connections: {err}");
}
}
});
}
/// Change Clash mode (rule/global/direct/script)
pub async fn change_clash_mode(mode: String) {
let mut mapping = Mapping::new();
mapping.insert(Value::from("mode"), mode.clone().into());
// Convert YAML mapping to JSON Value
let json_value = serde_json::json!({
"mode": mode
});
log::debug!(target: "app", "change clash mode to {mode}");
match handle::Handle::mihomo()
.await
.patch_base_config(&json_value)
.await
{
Ok(_) => {
// 更新订阅
Config::clash().await.data_mut().patch_config(mapping);
// 分离数据获取和异步调用
let clash_data = Config::clash().await.data_mut().clone();
if clash_data.save_config().await.is_ok() {
handle::Handle::refresh_clash();
logging_error!(Type::Tray, true, tray::Tray::global().update_menu().await);
logging_error!(Type::Tray, true, tray::Tray::global().update_icon().await);
}
let is_auto_close_connection = Config::verge()
.await
.data_mut()
.auto_close_connection
.unwrap_or(false);
if is_auto_close_connection {
after_change_clash_mode();
}
}
Err(err) => log::error!(target: "app", "{err}"),
}
}
/// Test connection delay to a URL
pub async fn test_delay(url: String) -> anyhow::Result<u32> {
use crate::utils::network::{NetworkManager, ProxyType};
use tokio::time::Instant;
let tun_mode = Config::verge()
.await
.latest_ref()
.enable_tun_mode
.unwrap_or(false);
// 如果是TUN模式不使用代理否则使用自身代理
let proxy_type = if !tun_mode {
ProxyType::Localhost
} else {
ProxyType::None
};
let user_agent = Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0".to_string());
let start = Instant::now();
let response = NetworkManager::new()
.get_with_interrupt(&url, proxy_type, Some(10), user_agent, false)
.await;
match response {
Ok(response) => {
log::trace!(target: "app", "test_delay response: {response:#?}");
if response.status().is_success() {
Ok(start.elapsed().as_millis() as u32)
} else {
Ok(10000u32)
}
}
Err(err) => {
log::trace!(target: "app", "test_delay error: {err:#?}");
Err(err)
}
}
}