style: adjust rustfmt max_width to 120

This commit is contained in:
Tunglies
2025-12-06 10:31:31 +08:00
parent c888703b05
commit 2ca8e6716d
66 changed files with 510 additions and 1616 deletions
+7 -31
View File
@@ -84,10 +84,7 @@ impl WebDavClient {
} else {
// 释放锁后获取异步配置
let verge = Config::verge().await.data_arc();
if verge.webdav_url.is_none()
|| verge.webdav_username.is_none()
|| verge.webdav_password.is_none()
{
if verge.webdav_url.is_none() || verge.webdav_username.is_none() || verge.webdav_password.is_none() {
let msg: String =
"Unable to create web dav client, please make sure the webdav config is correct".into();
return Err(anyhow::Error::msg(msg));
@@ -129,10 +126,7 @@ impl WebDavClient {
.build()?,
)
.set_host(config.url.into())
.set_auth(reqwest_dav::Auth::Basic(
config.username.into(),
config.password.into(),
))
.set_auth(reqwest_dav::Auth::Basic(config.username.into(), config.password.into()))
.build()?;
// 尝试检查目录是否存在,如果不存在尝试创建
@@ -144,18 +138,10 @@ impl WebDavClient {
match client.mkcol(dirs::BACKUP_DIR).await {
Ok(_) => logging!(info, Type::Backup, "Successfully created backup directory"),
Err(e) => {
logging!(
warn,
Type::Backup,
"Warning: Failed to create backup directory: {}",
e
);
logging!(warn, Type::Backup, "Warning: Failed to create backup directory: {}", e);
// 清除缓存,强制下次重新尝试
self.reset();
return Err(anyhow::Error::msg(format!(
"Failed to create backup directory: {}",
e
)));
return Err(anyhow::Error::msg(format!("Failed to create backup directory: {}", e)));
}
}
}
@@ -191,11 +177,7 @@ impl WebDavClient {
match upload_result {
Err(_) => {
logging!(
warn,
Type::Backup,
"Warning: Upload timed out, retrying once"
);
logging!(warn, Type::Backup, "Warning: Upload timed out, retrying once");
tokio::time::sleep(Duration::from_millis(500)).await;
timeout(
Duration::from_secs(TIMEOUT_UPLOAD),
@@ -206,11 +188,7 @@ impl WebDavClient {
}
Ok(Err(e)) => {
logging!(
warn,
Type::Backup,
"Warning: Upload failed, retrying once: {e}"
);
logging!(warn, Type::Backup, "Warning: Upload failed, retrying once: {e}");
tokio::time::sleep(Duration::from_millis(500)).await;
timeout(
Duration::from_secs(TIMEOUT_UPLOAD),
@@ -243,9 +221,7 @@ impl WebDavClient {
let path = format!("{}/", dirs::BACKUP_DIR);
let fut = async {
let files = client
.list(path.as_str(), reqwest_dav::Depth::Number(1))
.await?;
let files = client.list(path.as_str(), reqwest_dav::Depth::Number(1)).await?;
let mut final_files = Vec::new();
for file in files {
if let ListEntity::File(file) = file {
+8 -35
View File
@@ -177,10 +177,7 @@ impl Hotkey {
"Failed to reactivate subscriptions via hotkey: {}",
err
);
handle::Handle::notice_message(
"reactivate_profiles::error",
err.to_string(),
);
handle::Handle::notice_message("reactivate_profiles::error", err.to_string());
}
});
}
@@ -205,8 +202,7 @@ impl Hotkey {
pub async fn register_system_hotkey(&self, hotkey: SystemHotkey) -> Result<()> {
let hotkey_str = hotkey.to_string();
let function = hotkey.function();
self.register_hotkey_with_function(&hotkey_str, function)
.await
self.register_hotkey_with_function(&hotkey_str, function).await
}
#[cfg(target_os = "macos")]
@@ -218,11 +214,7 @@ impl Hotkey {
/// Register a hotkey with function enum
#[allow(clippy::unused_async)]
pub async fn register_hotkey_with_function(
&self,
hotkey: &str,
function: HotkeyFunction,
) -> Result<()> {
pub async fn register_hotkey_with_function(&self, hotkey: &str, function: HotkeyFunction) -> Result<()> {
let app_handle = handle::Handle::app_handle();
let manager = app_handle.global_shortcut();
@@ -261,11 +253,8 @@ impl Hotkey {
AsyncHandler::spawn(move || async move {
logging!(debug, Type::Hotkey, "Executing function directly");
let is_enable_global_hotkey = Config::verge()
.await
.data_arc()
.enable_global_hotkey
.unwrap_or(true);
let is_enable_global_hotkey =
Config::verge().await.data_arc().enable_global_hotkey.unwrap_or(true);
if is_enable_global_hotkey {
Self::execute_function(function);
@@ -312,12 +301,7 @@ impl Hotkey {
let hotkeys = verge.data_arc().hotkeys.clone();
if let Some(hotkeys) = hotkeys {
logging!(
debug,
Type::Hotkey,
"Has {} hotkeys need to register",
hotkeys.len()
);
logging!(debug, Type::Hotkey, "Has {} hotkeys need to register", hotkeys.len());
for hotkey in hotkeys.iter() {
let mut iter = hotkey.split(',');
@@ -326,13 +310,7 @@ impl Hotkey {
match (key, func) {
(Some(key), Some(func)) => {
logging!(
debug,
Type::Hotkey,
"Registering hotkey: {} -> {}",
key,
func
);
logging!(debug, Type::Hotkey, "Registering hotkey: {} -> {}", key, func);
if let Err(e) = self.register(key, func).await {
logging!(
error,
@@ -465,12 +443,7 @@ impl Drop for Hotkey {
fn drop(&mut self) {
let app_handle = handle::Handle::app_handle();
if let Err(e) = app_handle.global_shortcut().unregister_all() {
logging!(
error,
Type::Hotkey,
"Error unregistering all hotkeys: {:?}",
e
);
logging!(error, Type::Hotkey, "Error unregistering all hotkeys: {:?}", e);
}
}
}
+1 -4
View File
@@ -94,9 +94,6 @@ impl CoreManager {
}
async fn reload_config(&self, path: &str) -> Result<(), MihomoError> {
handle::Handle::mihomo()
.await
.reload_config(true, path)
.await
handle::Handle::mihomo().await.reload_config(true, path).await
}
}
+3 -12
View File
@@ -78,10 +78,7 @@ impl CoreManager {
fn after_core_process(&self) {
let app_handle = Handle::app_handle();
tauri_plugin_clash_verge_sysinfo::set_app_core_mode(
app_handle,
self.get_running_mode().to_string(),
);
tauri_plugin_clash_verge_sysinfo::set_app_core_mode(app_handle, self.get_running_mode().to_string());
}
#[cfg(target_os = "windows")]
@@ -89,11 +86,7 @@ impl CoreManager {
use crate::{config::Config, constants::timing};
use backoff::{Error as BackoffError, ExponentialBackoff};
let needs_service = Config::verge()
.await
.latest_arc()
.enable_tun_mode
.unwrap_or(false);
let needs_service = Config::verge().await.latest_arc().enable_tun_mode.unwrap_or(false);
if !needs_service {
return;
@@ -121,9 +114,7 @@ impl CoreManager {
if matches!(manager.current(), ServiceStatus::Ready) {
Ok(())
} else {
Err(BackoffError::transient(anyhow::anyhow!(
"Service not ready"
)))
Err(BackoffError::transient(anyhow::anyhow!("Service not ready")))
}
};
+3 -14
View File
@@ -54,8 +54,7 @@ impl CoreManager {
self.set_running_child_sidecar(child);
self.set_running_mode(RunningMode::Sidecar);
let shared_writer: SharedWriter =
std::sync::Arc::new(tokio::sync::Mutex::new(sidecar_writer().await?));
let shared_writer: SharedWriter = std::sync::Arc::new(tokio::sync::Mutex::new(sidecar_writer().await?));
AsyncHandler::spawn(|| async move {
while let Some(event) = rx.recv().await {
@@ -64,12 +63,7 @@ impl CoreManager {
| tauri_plugin_shell::process::CommandEvent::Stderr(line) => {
let mut now = DeferredNow::default();
let message = CompactString::from(String::from_utf8_lossy(&line).as_ref());
write_sidecar_log(
shared_writer.lock().await,
&mut now,
Level::Error,
&message,
);
write_sidecar_log(shared_writer.lock().await, &mut now, Level::Error, &message);
CLASH_LOGGER.append_log(message).await;
}
tauri_plugin_shell::process::CommandEvent::Terminated(term) => {
@@ -81,12 +75,7 @@ impl CoreManager {
} else {
CompactString::from("Process terminated")
};
write_sidecar_log(
shared_writer.lock().await,
&mut now,
Level::Info,
&message,
);
write_sidecar_log(shared_writer.lock().await, &mut now, Level::Info, &message);
CLASH_LOGGER.clear_logs().await;
break;
}
+9 -31
View File
@@ -80,12 +80,7 @@ impl NotificationSystem {
match result {
Ok(handle) => self.worker_handle = Some(handle),
Err(e) => logging!(
error,
Type::System,
"Failed to start notification worker: {}",
e
),
Err(e) => logging!(error, Type::System, "Failed to start notification worker: {}", e),
}
}
@@ -148,31 +143,19 @@ impl NotificationSystem {
}
}
fn serialize_event(
&self,
event: FrontendEvent,
) -> (&'static str, Result<serde_json::Value, serde_json::Error>) {
fn serialize_event(&self, event: FrontendEvent) -> (&'static str, Result<serde_json::Value, serde_json::Error>) {
use serde_json::json;
match event {
FrontendEvent::RefreshClash => ("verge://refresh-clash-config", Ok(json!("yes"))),
FrontendEvent::RefreshVerge => ("verge://refresh-verge-config", Ok(json!("yes"))),
FrontendEvent::NoticeMessage { status, message } => (
"verge://notice-message",
serde_json::to_value((status, message)),
),
FrontendEvent::ProfileChanged { current_profile_id } => {
("profile-changed", Ok(json!(current_profile_id)))
}
FrontendEvent::TimerUpdated { profile_index } => {
("verge://timer-updated", Ok(json!(profile_index)))
}
FrontendEvent::ProfileUpdateStarted { uid } => {
("profile-update-started", Ok(json!({ "uid": uid })))
}
FrontendEvent::ProfileUpdateCompleted { uid } => {
("profile-update-completed", Ok(json!({ "uid": uid })))
FrontendEvent::NoticeMessage { status, message } => {
("verge://notice-message", serde_json::to_value((status, message)))
}
FrontendEvent::ProfileChanged { current_profile_id } => ("profile-changed", Ok(json!(current_profile_id))),
FrontendEvent::TimerUpdated { profile_index } => ("verge://timer-updated", Ok(json!(profile_index))),
FrontendEvent::ProfileUpdateStarted { uid } => ("profile-update-started", Ok(json!({ "uid": uid }))),
FrontendEvent::ProfileUpdateCompleted { uid } => ("profile-update-completed", Ok(json!({ "uid": uid }))),
}
}
@@ -182,12 +165,7 @@ impl NotificationSystem {
let errors = self.stats.total_errors.load(Ordering::Relaxed);
if errors > retry::EVENT_EMIT_THRESHOLD && !self.emergency_mode.load(Ordering::Acquire) {
logging!(
warn,
Type::Frontend,
"Entering emergency mode after {} errors",
errors
);
logging!(warn, Type::Frontend, "Entering emergency mode after {} errors", errors);
self.emergency_mode.store(true, Ordering::Release);
}
}
+18 -56
View File
@@ -50,9 +50,7 @@ async fn uninstall_service() -> Result<()> {
let level = token.privilege_level()?;
let status = match level {
PrivilegeLevel::NotPrivileged => RunasCommand::new(uninstall_path).show(false).status()?,
_ => StdCommand::new(uninstall_path)
.creation_flags(0x08000000)
.status()?,
_ => StdCommand::new(uninstall_path).creation_flags(0x08000000).status()?,
};
if !status.success() {
@@ -85,16 +83,11 @@ async fn install_service() -> Result<()> {
let level = token.privilege_level()?;
let status = match level {
PrivilegeLevel::NotPrivileged => RunasCommand::new(install_path).show(false).status()?,
_ => StdCommand::new(install_path)
.creation_flags(0x08000000)
.status()?,
_ => StdCommand::new(install_path).creation_flags(0x08000000).status()?,
};
if !status.success() {
bail!(
"failed to install service with status {}",
status.code().unwrap_or(-1)
);
bail!("failed to install service with status {}", status.code().unwrap_or(-1));
}
Ok(())
@@ -123,8 +116,7 @@ async fn reinstall_service() -> Result<()> {
async fn uninstall_service() -> Result<()> {
logging!(info, Type::Service, "uninstall service");
let uninstall_path =
tauri::utils::platform::current_exe()?.with_file_name("clash-verge-service-uninstall");
let uninstall_path = tauri::utils::platform::current_exe()?.with_file_name("clash-verge-service-uninstall");
if !uninstall_path.exists() {
bail!(format!("uninstaller not found: {uninstall_path:?}"));
@@ -181,8 +173,7 @@ async fn uninstall_service() -> Result<()> {
async fn install_service() -> Result<()> {
logging!(info, Type::Service, "install service");
let install_path =
tauri::utils::platform::current_exe()?.with_file_name("clash-verge-service-install");
let install_path = tauri::utils::platform::current_exe()?.with_file_name("clash-verge-service-install");
if !install_path.exists() {
bail!(format!("installer not found: {install_path:?}"));
@@ -225,10 +216,7 @@ async fn install_service() -> Result<()> {
);
if !status.success() {
bail!(
"failed to install service with status {}",
status.code().unwrap_or(-1)
);
bail!("failed to install service with status {}", status.code().unwrap_or(-1));
}
Ok(())
@@ -276,15 +264,12 @@ async fn uninstall_service() -> Result<()> {
crate::utils::i18n::sync_locale().await;
let prompt = rust_i18n::t!("service.adminUninstallPrompt").to_string();
let command = format!(
r#"do shell script "sudo '{uninstall_shell}'" with administrator privileges with prompt "{prompt}""#
);
let command =
format!(r#"do shell script "sudo '{uninstall_shell}'" with administrator privileges with prompt "{prompt}""#);
// logging!(debug, Type::Service, "uninstall command: {}", command);
let status = StdCommand::new("osascript")
.args(vec!["-e", &command])
.status()?;
let status = StdCommand::new("osascript").args(vec!["-e", &command]).status()?;
if !status.success() {
bail!(
@@ -312,19 +297,13 @@ async fn install_service() -> Result<()> {
crate::utils::i18n::sync_locale().await;
let prompt = rust_i18n::t!("service.adminInstallPrompt").to_string();
let command = format!(
r#"do shell script "sudo '{install_shell}'" with administrator privileges with prompt "{prompt}""#
);
let command =
format!(r#"do shell script "sudo '{install_shell}'" with administrator privileges with prompt "{prompt}""#);
let status = StdCommand::new("osascript")
.args(vec!["-e", &command])
.status()?;
let status = StdCommand::new("osascript").args(vec!["-e", &command]).status()?;
if !status.success() {
bail!(
"failed to install service with status {}",
status.code().unwrap_or(-1)
);
bail!("failed to install service with status {}", status.code().unwrap_or(-1));
}
Ok(())
@@ -362,19 +341,13 @@ async fn check_service_version() -> Result<String> {
let version_arc: Result<String> = {
logging!(info, Type::Service, "开始检查服务版本 (IPC)");
let result = clash_verge_service_ipc::get_version().await;
logging!(
debug,
Type::Service,
"检查服务版本 (IPC) 结果: {:?}",
result
);
logging!(debug, Type::Service, "检查服务版本 (IPC) 结果: {:?}", result);
// 检查错误信息是否是JSON序列化错误或预期值错误,以适配老版本服务
// 这可能是因为老版本服务的API不兼容,导致无法正确解析响应
// 如果是这种情况,直接返回空字符串,表示无法获取版本
if let Err(e) = result.as_ref()
&& (e.to_string().contains("JSON serialization error")
|| e.to_string().contains("expected value"))
&& (e.to_string().contains("JSON serialization error") || e.to_string().contains("expected value"))
{
logging!(
warn,
@@ -468,12 +441,7 @@ pub(super) async fn get_clash_logs_by_service() -> Result<Vec<CompactString>> {
if response.code > 0 {
let err_msg = response.message;
logging!(
error,
Type::Service,
"获取服务模式下的 Clash 日志失败: {}",
err_msg
);
logging!(error, Type::Service, "获取服务模式下的 Clash 日志失败: {}", err_msg);
bail!(err_msg);
}
@@ -594,12 +562,7 @@ impl ServiceManager {
self.0 = ServiceStatus::Unavailable("Service Uninstalled".into());
}
ServiceStatus::Unavailable(reason) => {
logging!(
info,
Type::Service,
"服务不可用: {},将使用Sidecar模式",
reason
);
logging!(info, Type::Service, "服务不可用: {},将使用Sidecar模式", reason);
self.0 = ServiceStatus::Unavailable(reason.clone());
return Err(anyhow::anyhow!("服务不可用: {}", reason));
}
@@ -609,5 +572,4 @@ impl ServiceManager {
}
}
pub static SERVICE_MANAGER: Lazy<Mutex<ServiceManager>> =
Lazy::new(|| Mutex::new(ServiceManager::default()));
pub static SERVICE_MANAGER: Lazy<Mutex<ServiceManager>> = Lazy::new(|| Mutex::new(ServiceManager::default()));
+7 -22
View File
@@ -35,10 +35,7 @@ impl Default for Sysopt {
reset_sysproxy: AtomicBool::new(false),
#[cfg(not(target_os = "windows"))]
inner_proxy: Arc::new(RwLock::new((Sysproxy::default(), Autoproxy::default()))),
guard: Arc::new(RwLock::new(GuardMonitor::new(
GuardType::None,
Duration::from_secs(30),
))),
guard: Arc::new(RwLock::new(GuardMonitor::new(GuardType::None, Duration::from_secs(30)))),
}
}
}
@@ -52,11 +49,7 @@ static DEFAULT_BYPASS: &str =
"127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,<local>";
async fn get_bypass() -> String {
let use_default = Config::verge()
.await
.latest_arc()
.use_default_bypass
.unwrap_or(true);
let use_default = Config::verge().await.latest_arc().use_default_bypass.unwrap_or(true);
let res = {
let verge = Config::verge().await;
let verge = verge.latest_arc();
@@ -136,9 +129,9 @@ impl Sysopt {
);
{
let guard = self.access_guard();
guard.write().set_interval(Duration::from_secs(
verge.proxy_guard_duration.unwrap_or(30),
));
guard
.write()
.set_interval(Duration::from_secs(verge.proxy_guard_duration.unwrap_or(30)));
}
logging!(info, Type::Core, "Starting system proxy guard...");
{
@@ -180,10 +173,7 @@ impl Sysopt {
(
verge.enable_system_proxy.unwrap_or(false),
verge.proxy_auto_config.unwrap_or(false),
verge
.proxy_host
.clone()
.unwrap_or_else(|| String::from("127.0.0.1")),
verge.proxy_host.clone().unwrap_or_else(|| String::from("127.0.0.1")),
)
};
@@ -306,12 +296,7 @@ impl Sysopt {
pub async fn update_launch(&self) -> Result<()> {
let enable_auto_launch = { Config::verge().await.latest_arc().enable_auto_launch };
let is_enable = enable_auto_launch.unwrap_or(false);
logging!(
info,
Type::System,
"Setting auto-launch state to: {:?}",
is_enable
);
logging!(info, Type::System, "Setting auto-launch state to: {:?}", is_enable);
// 首先尝试使用快捷方式方法
#[cfg(target_os = "windows")]
+30 -72
View File
@@ -75,12 +75,7 @@ impl Timer {
// Log timer info first
{
let timer_map = self.timer_map.read();
logging!(
info,
Type::Timer,
"已注册的定时任务数量: {}",
timer_map.len()
);
logging!(info, Type::Timer, "已注册的定时任务数量: {}", timer_map.len());
for (uid, task) in timer_map.iter() {
logging!(
@@ -97,32 +92,30 @@ impl Timer {
let cur_timestamp = chrono::Local::now().timestamp();
// Collect profiles that need immediate update
let profiles_to_update =
if let Some(items) = Config::profiles().await.latest_arc().get_items() {
items
.iter()
.filter_map(|item| {
let allow_auto_update =
item.option.as_ref()?.allow_auto_update.unwrap_or_default();
if !allow_auto_update {
return None;
}
let profiles_to_update = if let Some(items) = Config::profiles().await.latest_arc().get_items() {
items
.iter()
.filter_map(|item| {
let allow_auto_update = item.option.as_ref()?.allow_auto_update.unwrap_or_default();
if !allow_auto_update {
return None;
}
let interval = item.option.as_ref()?.update_interval? as i64;
let updated = item.updated? as i64;
let uid = item.uid.as_ref()?;
let interval = item.option.as_ref()?.update_interval? as i64;
let updated = item.updated? as i64;
let uid = item.uid.as_ref()?;
if interval > 0 && cur_timestamp - updated >= interval * 60 {
logging!(info, Type::Timer, "需要立即更新的配置: uid={}", uid);
Some(uid.clone())
} else {
None
}
})
.collect::<Vec<String>>()
} else {
Vec::new()
};
if interval > 0 && cur_timestamp - updated >= interval * 60 {
logging!(info, Type::Timer, "需要立即更新的配置: uid={}", uid);
Some(uid.clone())
} else {
None
}
})
.collect::<Vec<String>>()
} else {
Vec::new()
};
// Advance tasks outside of locks to minimize lock contention
if !profiles_to_update.is_empty() {
@@ -178,12 +171,7 @@ impl Timer {
return Ok(());
}
logging!(
info,
Type::Timer,
"Refreshing {} timer tasks",
diff_map.len()
);
logging!(info, Type::Timer, "Refreshing {} timer tasks", diff_map.len());
// Apply changes - first collect operations to perform without holding locks
let mut operations_to_add: Vec<(String, TaskID, u64)> = Vec::new();
@@ -286,12 +274,7 @@ impl Timer {
}
}
logging!(
debug,
Type::Timer,
"生成的定时更新配置数量: {}",
new_map.len()
);
logging!(debug, Type::Timer, "生成的定时更新配置数量: {}", new_map.len());
new_map
}
@@ -302,12 +285,7 @@ impl Timer {
// Read lock for comparing current state
let timer_map = self.timer_map.read();
logging!(
debug,
Type::Timer,
"当前 timer_map 大小: {}",
timer_map.len()
);
logging!(debug, Type::Timer, "当前 timer_map 大小: {}", timer_map.len());
// Find tasks to modify or delete
for (uid, task) in timer_map.iter() {
@@ -364,13 +342,7 @@ impl Timer {
}
/// Add a timer task with better error handling
fn add_task(
&self,
delay_timer: &DelayTimer,
uid: String,
tid: TaskID,
minutes: u64,
) -> Result<()> {
fn add_task(&self, delay_timer: &DelayTimer, uid: String, tid: TaskID, minutes: u64) -> Result<()> {
logging!(
info,
Type::Timer,
@@ -394,9 +366,7 @@ impl Timer {
})
.context("failed to create timer task")?;
delay_timer
.add_task(task)
.context("failed to add timer task")?;
delay_timer.add_task(task).context("failed to add timer task")?;
Ok(())
}
@@ -443,13 +413,7 @@ impl Timer {
// Calculate next update time
if updated > 0 && task_interval > 0 {
let next_time = updated + (task_interval as i64 * 60);
logging!(
info,
Type::Timer,
"计算得到下次更新时间: {}, uid={}",
next_time,
uid
);
logging!(info, Type::Timer, "计算得到下次更新时间: {}, uid={}", next_time, uid);
Some(next_time)
} else {
logging!(
@@ -483,13 +447,7 @@ impl Timer {
Self::emit_update_event(uid, true);
let is_current = Config::profiles().await.latest_arc().current.as_ref() == Some(uid);
logging!(
info,
Type::Timer,
"配置 {} 是否为当前激活配置: {}",
uid,
is_current
);
logging!(info, Type::Timer, "配置 {} 是否为当前激活配置: {}", uid, is_current);
feat::update_profile(uid, None, is_current, false).await
})
+56 -207
View File
@@ -93,29 +93,17 @@ impl TrayState {
}
#[cfg(target_os = "macos")]
{
let tray_icon_colorful = verge
.tray_icon
.clone()
.unwrap_or_else(|| "monochrome".into());
let tray_icon_colorful = verge.tray_icon.clone().unwrap_or_else(|| "monochrome".into());
if tray_icon_colorful == "monochrome" {
(
false,
include_bytes!("../../../icons/tray-icon-mono.ico").to_vec(),
)
(false, include_bytes!("../../../icons/tray-icon-mono.ico").to_vec())
} else {
(
false,
include_bytes!("../../../icons/tray-icon.ico").to_vec(),
)
(false, include_bytes!("../../../icons/tray-icon.ico").to_vec())
}
}
#[cfg(not(target_os = "macos"))]
{
(
false,
include_bytes!("../../../icons/tray-icon.ico").to_vec(),
)
(false, include_bytes!("../../../icons/tray-icon.ico").to_vec())
}
}
@@ -129,29 +117,20 @@ impl TrayState {
}
#[cfg(target_os = "macos")]
{
let tray_icon_colorful = verge
.tray_icon
.clone()
.unwrap_or_else(|| "monochrome".into());
let tray_icon_colorful = verge.tray_icon.clone().unwrap_or_else(|| "monochrome".into());
if tray_icon_colorful == "monochrome" {
(
false,
include_bytes!("../../../icons/tray-icon-sys-mono-new.ico").to_vec(),
)
} else {
(
false,
include_bytes!("../../../icons/tray-icon-sys.ico").to_vec(),
)
(false, include_bytes!("../../../icons/tray-icon-sys.ico").to_vec())
}
}
#[cfg(not(target_os = "macos"))]
{
(
false,
include_bytes!("../../../icons/tray-icon-sys.ico").to_vec(),
)
(false, include_bytes!("../../../icons/tray-icon-sys.ico").to_vec())
}
}
@@ -165,28 +144,19 @@ impl TrayState {
}
#[cfg(target_os = "macos")]
{
let tray_icon_colorful = verge
.tray_icon
.clone()
.unwrap_or_else(|| "monochrome".into());
let tray_icon_colorful = verge.tray_icon.clone().unwrap_or_else(|| "monochrome".into());
if tray_icon_colorful == "monochrome" {
(
false,
include_bytes!("../../../icons/tray-icon-tun-mono-new.ico").to_vec(),
)
} else {
(
false,
include_bytes!("../../../icons/tray-icon-tun.ico").to_vec(),
)
(false, include_bytes!("../../../icons/tray-icon-tun.ico").to_vec())
}
}
#[cfg(not(target_os = "macos"))]
{
(
false,
include_bytes!("../../../icons/tray-icon-tun.ico").to_vec(),
)
(false, include_bytes!("../../../icons/tray-icon-tun.ico").to_vec())
}
}
}
@@ -304,8 +274,8 @@ impl Tray {
let verge = Config::verge().await.latest_arc();
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
let tun_mode_available = is_current_app_handle_admin(app_handle)
|| service::is_service_available().await.is_ok();
let tun_mode_available =
is_current_app_handle_admin(app_handle) || service::is_service_available().await.is_ok();
let mode = {
Config::clash()
.await
@@ -339,11 +309,7 @@ impl Tray {
Ok(())
}
None => {
logging!(
warn,
Type::Tray,
"Failed to update tray menu: tray not found"
);
logging!(warn, Type::Tray, "Failed to update tray menu: tray not found");
Ok(())
}
}
@@ -362,11 +328,7 @@ impl Tray {
let tray = match app_handle.tray_by_id("main") {
Some(tray) => tray,
None => {
logging!(
warn,
Type::Tray,
"Failed to update tray icon: tray not found"
);
logging!(warn, Type::Tray, "Failed to update tray icon: tray not found");
return Ok(());
}
};
@@ -381,10 +343,7 @@ impl Tray {
(false, false) => TrayState::get_common_tray_icon(verge).await,
};
let colorful = verge
.tray_icon
.clone()
.unwrap_or_else(|| "monochrome".into());
let colorful = verge.tray_icon.clone().unwrap_or_else(|| "monochrome".into());
let is_colorful = colorful == "colorful";
let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?));
@@ -404,11 +363,7 @@ impl Tray {
let tray = match app_handle.tray_by_id("main") {
Some(tray) => tray,
None => {
logging!(
warn,
Type::Tray,
"Failed to update tray icon: tray not found"
);
logging!(warn, Type::Tray, "Failed to update tray icon: tray not found");
return Ok(());
}
};
@@ -488,11 +443,7 @@ impl Tray {
if let Some(tray) = app_handle.tray_by_id("main") {
let _ = tray.set_tooltip(Some(&tooltip));
} else {
logging!(
warn,
Type::Tray,
"Failed to update tray tooltip: tray not found"
);
logging!(warn, Type::Tray, "Failed to update tray tooltip: tray not found");
}
Ok(())
@@ -525,9 +476,7 @@ impl Tray {
let icon = tauri::image::Image::from_bytes(&icon_bytes)?;
#[cfg(target_os = "linux")]
let builder = TrayIconBuilder::with_id("main")
.icon(icon)
.icon_as_template(false);
let builder = TrayIconBuilder::with_id("main").icon(icon).icon_as_template(false);
#[cfg(any(target_os = "macos", target_os = "windows"))]
let show_menu_on_left_click = {
@@ -538,9 +487,7 @@ impl Tray {
};
#[cfg(not(target_os = "linux"))]
let mut builder = TrayIconBuilder::with_id("main")
.icon(icon)
.icon_as_template(false);
let mut builder = TrayIconBuilder::with_id("main").icon(icon).icon_as_template(false);
#[cfg(any(target_os = "macos", target_os = "windows"))]
{
@@ -679,18 +626,9 @@ fn create_subcreate_proxy_menu_item(
let display_text = format!("{} | {}", proxy_str, delay_text);
CheckMenuItem::with_id(
app_handle,
item_id,
display_text,
true,
is_selected,
None::<&str>,
)
.map_err(|e| {
logging!(warn, Type::Tray, "Failed to create proxy menu item: {}", e)
})
.ok()
CheckMenuItem::with_id(app_handle, item_id, display_text, true, is_selected, None::<&str>)
.map_err(|e| logging!(warn, Type::Tray, "Failed to create proxy menu item: {}", e))
.ok()
})
.collect();
@@ -700,10 +638,8 @@ fn create_subcreate_proxy_menu_item(
let group_display_name = group_name.to_string();
let group_items_refs: Vec<&dyn IsMenuItem<Wry>> = group_items
.iter()
.map(|item| item as &dyn IsMenuItem<Wry>)
.collect();
let group_items_refs: Vec<&dyn IsMenuItem<Wry>> =
group_items.iter().map(|item| item as &dyn IsMenuItem<Wry>).collect();
if let Ok(submenu) = Submenu::with_id_and_items(
app_handle,
@@ -715,34 +651,23 @@ fn create_subcreate_proxy_menu_item(
let insertion_index = submenus.len();
submenus.push((group_name.into(), insertion_index, submenu));
} else {
logging!(
warn,
Type::Tray,
"Failed to create proxy group submenu: {}",
group_name
);
logging!(warn, Type::Tray, "Failed to create proxy group submenu: {}", group_name);
}
}
}
if let Some(order_map) = proxy_group_order_map.as_ref() {
submenus.sort_by(
|(name_a, original_index_a, _), (name_b, original_index_b, _)| match (
order_map.get(name_a),
order_map.get(name_b),
) {
submenus.sort_by(|(name_a, original_index_a, _), (name_b, original_index_b, _)| {
match (order_map.get(name_a), order_map.get(name_b)) {
(Some(index_a), Some(index_b)) => index_a.cmp(index_b),
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => original_index_a.cmp(original_index_b),
},
);
}
});
}
submenus
.into_iter()
.map(|(_, _, submenu)| submenu)
.collect()
submenus.into_iter().map(|(_, _, submenu)| submenu).collect()
};
proxy_submenus
}
@@ -825,15 +750,14 @@ async fn create_tray_menu(
.unwrap_or_default()
});
let proxy_group_order_map: Option<
HashMap<smartstring::SmartString<smartstring::LazyCompact>, usize>,
> = runtime_proxy_groups_order.as_ref().map(|group_names| {
group_names
.iter()
.enumerate()
.map(|(index, name)| (name.clone(), index))
.collect::<HashMap<String, usize>>()
});
let proxy_group_order_map: Option<HashMap<smartstring::SmartString<smartstring::LazyCompact>, usize>> =
runtime_proxy_groups_order.as_ref().map(|group_names| {
group_names
.iter()
.enumerate()
.map(|(index, name)| (name.clone(), index))
.collect::<HashMap<String, usize>>()
});
let verge_settings = Config::verge().await.latest_arc();
let show_proxy_groups_inline = verge_settings.tray_inline_proxy_groups.unwrap_or(true);
@@ -842,8 +766,7 @@ async fn create_tray_menu(
let hotkeys = create_hotkeys(&verge_settings.hotkeys);
let profile_menu_items: Vec<CheckMenuItem<Wry>> =
create_profile_menu_item(app_handle, profiles_preview)?;
let profile_menu_items: Vec<CheckMenuItem<Wry>> = create_profile_menu_item(app_handle, profiles_preview)?;
// Pre-fetch all localized strings
let texts = MenuTexts::new();
@@ -915,19 +838,11 @@ async fn create_tray_menu(
&profile_menu_items_refs,
)?;
let proxy_sub_menus = create_subcreate_proxy_menu_item(
app_handle,
current_proxy_mode,
proxy_group_order_map,
proxy_nodes_data,
);
let proxy_sub_menus =
create_subcreate_proxy_menu_item(app_handle, current_proxy_mode, proxy_group_order_map, proxy_nodes_data);
let (proxies_menu, inline_proxy_items) = create_proxy_menu_item(
app_handle,
show_proxy_groups_inline,
proxy_sub_menus,
&texts.proxies,
)?;
let (proxies_menu, inline_proxy_items) =
create_proxy_menu_item(app_handle, show_proxy_groups_inline, proxy_sub_menus, &texts.proxies)?;
let system_proxy = &CheckMenuItem::with_id(
app_handle,
@@ -964,66 +879,24 @@ async fn create_tray_menu(
hotkeys.get("entry_lightweight_mode").map(|s| s.as_str()),
)?;
let copy_env = &MenuItem::with_id(
app_handle,
MenuIds::COPY_ENV,
&texts.copy_env,
true,
None::<&str>,
)?;
let copy_env = &MenuItem::with_id(app_handle, MenuIds::COPY_ENV, &texts.copy_env, true, None::<&str>)?;
let open_app_dir = &MenuItem::with_id(
app_handle,
MenuIds::CONF_DIR,
&texts.conf_dir,
true,
None::<&str>,
)?;
let open_app_dir = &MenuItem::with_id(app_handle, MenuIds::CONF_DIR, &texts.conf_dir, true, None::<&str>)?;
let open_core_dir = &MenuItem::with_id(
app_handle,
MenuIds::CORE_DIR,
&texts.core_dir,
true,
None::<&str>,
)?;
let open_core_dir = &MenuItem::with_id(app_handle, MenuIds::CORE_DIR, &texts.core_dir, true, None::<&str>)?;
let open_logs_dir = &MenuItem::with_id(
app_handle,
MenuIds::LOGS_DIR,
&texts.logs_dir,
true,
None::<&str>,
)?;
let open_logs_dir = &MenuItem::with_id(app_handle, MenuIds::LOGS_DIR, &texts.logs_dir, true, None::<&str>)?;
let open_app_log = &MenuItem::with_id(
app_handle,
MenuIds::APP_LOG,
&texts.app_log,
true,
None::<&str>,
)?;
let open_app_log = &MenuItem::with_id(app_handle, MenuIds::APP_LOG, &texts.app_log, true, None::<&str>)?;
let open_core_log = &MenuItem::with_id(
app_handle,
MenuIds::CORE_LOG,
&texts.core_log,
true,
None::<&str>,
)?;
let open_core_log = &MenuItem::with_id(app_handle, MenuIds::CORE_LOG, &texts.core_log, true, None::<&str>)?;
let open_dir = &Submenu::with_id_and_items(
app_handle,
MenuIds::OPEN_DIR,
&texts.open_dir,
true,
&[
open_app_dir,
open_core_dir,
open_logs_dir,
open_app_log,
open_core_log,
],
&[open_app_dir, open_core_dir, open_logs_dir, open_app_log, open_core_log],
)?;
let restart_clash = &MenuItem::with_id(
@@ -1034,13 +907,7 @@ async fn create_tray_menu(
None::<&str>,
)?;
let restart_app = &MenuItem::with_id(
app_handle,
MenuIds::RESTART_APP,
&texts.restart_app,
true,
None::<&str>,
)?;
let restart_app = &MenuItem::with_id(app_handle, MenuIds::RESTART_APP, &texts.restart_app, true, None::<&str>)?;
let app_version = &MenuItem::with_id(
app_handle,
@@ -1064,19 +931,12 @@ async fn create_tray_menu(
],
)?;
let quit = &MenuItem::with_id(
app_handle,
MenuIds::EXIT,
&texts.exit,
true,
Some("CmdOrControl+Q"),
)?;
let quit = &MenuItem::with_id(app_handle, MenuIds::EXIT, &texts.exit, true, Some("CmdOrControl+Q"))?;
let separator = &PredefinedMenuItem::separator(app_handle)?;
// 动态构建菜单项
let mut menu_items: Vec<&dyn IsMenuItem<Wry>> =
vec![open_window, outbound_modes, separator, profiles];
let mut menu_items: Vec<&dyn IsMenuItem<Wry>> = vec![open_window, outbound_modes, separator, profiles];
// 如果有代理节点,添加代理节点菜单
if show_proxy_groups_inline {
@@ -1099,9 +959,7 @@ async fn create_tray_menu(
quit as &dyn IsMenuItem<Wry>,
]);
let menu = tauri::menu::MenuBuilder::new(app_handle)
.items(&menu_items)
.build()?;
let menu = tauri::menu::MenuBuilder::new(app_handle).items(&menu_items).build()?;
Ok(menu)
}
@@ -1132,11 +990,7 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
}
MenuIds::CLOSE_ALL_CONNECTIONS => {
if let Err(err) = handle::Handle::mihomo().await.close_all_connections().await {
logging!(
error,
Type::Tray,
"Failed to close all connections from tray: {err}"
);
logging!(error, Type::Tray, "Failed to close all connections from tray: {err}");
}
}
MenuIds::COPY_ENV => feat::copy_clash_env().await,
@@ -1188,12 +1042,7 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
feat::switch_proxy_node(group_name, proxy_name).await;
}
_ => {
logging!(
debug,
Type::Tray,
"Unhandled tray menu event: {:?}",
event.id
);
logging!(debug, Type::Tray, "Unhandled tray menu event: {:?}", event.id);
}
}
+12 -47
View File
@@ -45,17 +45,8 @@ impl CoreConfigValidator {
let content = match fs::read_to_string(path).await {
Ok(content) => content,
Err(err) => {
logging!(
warn,
Type::Validate,
"无法读取文件以检测类型: {}, 错误: {}",
path,
err
);
return Err(anyhow::anyhow!(
"Failed to read file to detect type: {}",
err
));
logging!(warn, Type::Validate, "无法读取文件以检测类型: {}, 错误: {}", path, err);
return Err(anyhow::anyhow!("Failed to read file to detect type: {}", err));
}
};
@@ -102,12 +93,7 @@ impl CoreConfigValidator {
}
// 默认情况:无法确定时,假设为非脚本文件(更安全)
logging!(
debug,
Type::Validate,
"无法确定文件类型,默认当作YAML处理: {}",
path
);
logging!(debug, Type::Validate, "无法确定文件类型,默认当作YAML处理: {}", path);
Ok(false)
}
@@ -188,10 +174,7 @@ impl CoreConfigValidator {
}
/// 验证指定的配置文件
pub async fn validate_config_file(
config_path: &str,
is_merge_file: Option<bool>,
) -> Result<(bool, String)> {
pub async fn validate_config_file(config_path: &str, is_merge_file: Option<bool>) -> Result<(bool, String)> {
// 检查程序是否正在退出,如果是则跳过验证
if handle::Handle::global().is_exiting() {
logging!(info, Type::Core, "应用正在退出,跳过验证");
@@ -207,12 +190,7 @@ impl CoreConfigValidator {
// 如果是合并文件且不是强制验证,执行语法检查但不进行完整验证
if is_merge_file.unwrap_or(false) {
logging!(
info,
Type::Validate,
"检测到Merge文件,仅进行语法检查: {}",
config_path
);
logging!(info, Type::Validate, "检测到Merge文件,仅进行语法检查: {}", config_path);
return Self::validate_file_syntax(config_path).await;
}
@@ -224,13 +202,7 @@ impl CoreConfigValidator {
Ok(result) => result,
Err(err) => {
// 如果无法确定文件类型,尝试使用Clash内核验证
logging!(
warn,
Type::Validate,
"无法确定文件类型: {}, 错误: {}",
config_path,
err
);
logging!(warn, Type::Validate, "无法确定文件类型: {}, 错误: {}", config_path, err);
return Self::validate_config_internal(config_path).await;
}
}
@@ -247,12 +219,7 @@ impl CoreConfigValidator {
}
// 对YAML配置文件使用Clash内核验证
logging!(
info,
Type::Validate,
"使用Clash内核验证配置文件: {}",
config_path
);
logging!(info, Type::Validate, "使用Clash内核验证配置文件: {}", config_path);
Self::validate_config_internal(config_path).await
}
@@ -275,13 +242,11 @@ impl CoreConfigValidator {
logging!(info, Type::Validate, "验证目录: {}", app_dir_str);
// 使用子进程运行clash验证配置
let command = app_handle.shell().sidecar(clash_core.as_str())?.args([
"-t",
"-d",
app_dir_str,
"-f",
config_path,
]);
let command =
app_handle
.shell()
.sidecar(clash_core.as_str())?
.args(["-t", "-d", app_dir_str, "-f", config_path]);
let output = command.output().await?;
let status = &output.status;