mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-25 13:12:07 +08:00
* refactor(ipc): generate bindings with Specta * fix(profile): project IPC inputs to consumed fields * fix(events): remove unused refresh payloads * fix(webdav): return only consumed backup metadata * fix(network): trim unused interface metadata * fix(sysinfo): return only displayed system fields * chore(knip): check generated runtime exports * fix(proxy): confirm runtime chain updates before UI changes * fix(clipboard): propagate proxy environment copy failures * refactor(dns): remove ignored runtime patch * refactor(core): trim unused upgrade response fields * refactor(ipc): avoid redundant response copies * refactor(proxy): clarify automatic proxy query naming * chore(tests): remove added IPC regression tests * refactor(ipc): enforce typed command boundaries * chore(contract): check generated bindings before push * refactor(ipc): remove unused proxy liveness payloads
145 lines
4.5 KiB
Rust
145 lines
4.5 KiB
Rust
use crate::core::notify::{Refresh, announce};
|
|
use crate::{
|
|
config::{Config, IVerge, MixedPort},
|
|
core::{
|
|
handle,
|
|
notification::{self, FailedOperation},
|
|
proxy_control,
|
|
},
|
|
utils::{
|
|
notification::{NotificationEvent, needs_system_notification, notify_event},
|
|
window_manager::WindowManager,
|
|
},
|
|
};
|
|
use anyhow::Context as _;
|
|
use clash_verge_logging::{Type, logging};
|
|
use std::env;
|
|
use tauri_plugin_clipboard_manager::ClipboardExt as _;
|
|
|
|
pub async fn toggle_system_proxy() -> Option<bool> {
|
|
let verge = Config::verge().await;
|
|
let current = verge.latest_arc().enable_system_proxy.unwrap_or(false);
|
|
let auto_close_connection = verge.latest_arc().auto_close_connection.unwrap_or(false);
|
|
|
|
if current
|
|
&& auto_close_connection
|
|
&& let Err(err) = handle::Handle::mihomo().close_all_connections().await
|
|
{
|
|
logging!(
|
|
error,
|
|
Type::ProxyMode,
|
|
"toggle system proxy: failed to close all connections: {err}"
|
|
);
|
|
}
|
|
|
|
let requested = !current;
|
|
let patch_result = notification::asking_for(
|
|
toggle_operation(requested),
|
|
Box::pin(super::patch_verge(
|
|
&IVerge {
|
|
enable_system_proxy: Some(requested),
|
|
..IVerge::default()
|
|
},
|
|
false,
|
|
)),
|
|
)
|
|
.await;
|
|
|
|
match patch_result {
|
|
Ok(_) => Some(requested),
|
|
Err(err) => {
|
|
logging!(error, Type::ProxyMode, "toggle system proxy failed: {err:#}");
|
|
report_toggle_failure(&err).await;
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn report_toggle_failure(error: &anyhow::Error) {
|
|
let recorded = proxy_control::is_reportable(error);
|
|
|
|
if recorded && needs_system_notification(WindowManager::get_main_window_state()) {
|
|
notify_event(NotificationEvent::SystemProxyFailed).await;
|
|
}
|
|
}
|
|
|
|
const fn toggle_operation(requested: bool) -> FailedOperation {
|
|
if requested {
|
|
FailedOperation::SystemProxyEnable
|
|
} else {
|
|
FailedOperation::SystemProxyDisable
|
|
}
|
|
}
|
|
|
|
pub async fn toggle_tun_mode(not_save_file: Option<bool>) -> bool {
|
|
let current = Config::verge().await.latest_arc().enable_tun_mode.unwrap_or(false);
|
|
let enable = !current;
|
|
|
|
match super::patch_verge(
|
|
&IVerge {
|
|
enable_tun_mode: Some(enable),
|
|
..IVerge::default()
|
|
},
|
|
not_save_file.unwrap_or(false),
|
|
)
|
|
.await
|
|
{
|
|
Ok(_) => {
|
|
announce(Refresh::Verge);
|
|
// Reconciliation may immediately disable unavailable TUN; report the resulting state.
|
|
Config::verge().await.latest_arc().enable_tun_mode.unwrap_or(false)
|
|
}
|
|
Err(err) => {
|
|
logging!(error, Type::ProxyMode, "toggle tun mode failed: {err:#}");
|
|
current
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn copy_clash_env() -> anyhow::Result<()> {
|
|
let env_ip = env::var("CLASH_VERGE_REV_IP").ok();
|
|
let verge_cfg = Config::verge().await.latest_arc();
|
|
let ip = env_ip
|
|
.as_deref()
|
|
.unwrap_or_else(|| verge_cfg.proxy_host.as_deref().unwrap_or("127.0.0.1"));
|
|
|
|
let app_handle = handle::Handle::app_handle();
|
|
// Clipboard output must use the core's live port, including merge-config overrides.
|
|
let port = MixedPort::effective().await;
|
|
let http_proxy = format!("http://{ip}:{port}");
|
|
let socks5_proxy = format!("socks5://{ip}:{port}");
|
|
|
|
let clipboard = app_handle.clipboard();
|
|
|
|
let default_env = {
|
|
#[cfg(not(target_os = "windows"))]
|
|
{
|
|
"bash"
|
|
}
|
|
#[cfg(target_os = "windows")]
|
|
{
|
|
"powershell"
|
|
}
|
|
};
|
|
let env_type = verge_cfg.env_type.as_deref().unwrap_or(default_env);
|
|
|
|
let export_text = match env_type {
|
|
"bash" => format!("export https_proxy={http_proxy} http_proxy={http_proxy} all_proxy={socks5_proxy}"),
|
|
"cmd" => format!("set http_proxy={http_proxy}\r\nset https_proxy={http_proxy}"),
|
|
"powershell" => {
|
|
format!("$env:HTTP_PROXY=\"{http_proxy}\"; $env:HTTPS_PROXY=\"{http_proxy}\"")
|
|
}
|
|
"nushell" => {
|
|
format!("load-env {{ http_proxy: \"{http_proxy}\", https_proxy: \"{http_proxy}\" }}")
|
|
}
|
|
"fish" => format!("set -x http_proxy {http_proxy}; set -x https_proxy {http_proxy}"),
|
|
_ => {
|
|
anyhow::bail!("Invalid environment variable format: {env_type}");
|
|
}
|
|
};
|
|
|
|
clipboard
|
|
.write_text(export_text)
|
|
.context("Failed to write proxy environment variables to clipboard")
|
|
}
|