diff --git a/.husky/pre-commit b/.husky/pre-commit index 8e0fa986..42383710 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,16 @@ +#!/bin/bash + pnpm pretty-quick --staged + +# 运行 clippy fmt +cargo fmt --manifest-path ./src-tauri/Cargo.toml + +if [ $? -ne 0 ]; then + echo "rustfmt failed to format the code. Please fix the issues and try again." + exit 1 +fi + +git add . + +# 允许提交 +exit 0 diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100644 index 00000000..591361b5 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,13 @@ +#!/bin/bash + +# 运行 clippy +cargo clippy --manifest-path ./src-tauri/Cargo.toml --fix + +# 如果 clippy 失败,阻止 push +if [ $? -ne 0 ]; then + echo "Clippy found issues in sub_crate. Please fix them before pushing." + exit 1 +fi + +# 允许 push +exit 0 \ No newline at end of file diff --git a/src-tauri/.clippy.toml b/src-tauri/.clippy.toml new file mode 100644 index 00000000..0e7ffd07 --- /dev/null +++ b/src-tauri/.clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = true \ No newline at end of file diff --git a/src-tauri/src/cmd/app.rs b/src-tauri/src/cmd/app.rs index 0d110c2d..4fbc2d1f 100644 --- a/src-tauri/src/cmd/app.rs +++ b/src-tauri/src/cmd/app.rs @@ -75,40 +75,41 @@ pub fn get_app_dir() -> CmdResult { pub async fn download_icon_cache(url: String, name: String) -> CmdResult { let icon_cache_dir = wrap_err!(dirs::app_home_dir())?.join("icons").join("cache"); let icon_path = icon_cache_dir.join(&name); - + // 如果文件已存在,直接返回路径 if icon_path.exists() { return Ok(icon_path.to_string_lossy().to_string()); } - + // 确保缓存目录存在 if !icon_cache_dir.exists() { let _ = std::fs::create_dir_all(&icon_cache_dir); } - + // 使用临时文件名来下载 let temp_path = icon_cache_dir.join(format!("{}.downloading", &name)); - + // 下载文件到临时位置 let response = wrap_err!(reqwest::get(&url).await)?; - + // 检查内容类型是否为图片 - let content_type = response.headers() + let content_type = response + .headers() .get(reqwest::header::CONTENT_TYPE) .and_then(|v| v.to_str().ok()) .unwrap_or(""); - + let is_image = content_type.starts_with("image/"); - + // 获取响应内容 let content = wrap_err!(response.bytes().await)?; - + // 检查内容是否为HTML (针对CDN错误页面) - let is_html = content.len() > 15 && - (content.starts_with(b" 15 + && (content.starts_with(b" CmdResult } } }; - + wrap_err!(std::io::copy(&mut content.as_ref(), &mut file))?; } - + // 再次检查目标文件是否已存在,避免重命名覆盖其他线程已完成的文件 if !icon_path.exists() { match std::fs::rename(&temp_path, &icon_path) { - Ok(_) => {}, + Ok(_) => {} Err(_) => { let _ = std::fs::remove_file(&temp_path); if icon_path.exists() { @@ -140,11 +141,11 @@ pub async fn download_icon_cache(url: String, name: String) -> CmdResult } else { let _ = std::fs::remove_file(&temp_path); } - + Ok(icon_path.to_string_lossy().to_string()) } else { let _ = std::fs::remove_file(&temp_path); - Err(format!("下载的内容不是有效图片: {}", url).into()) + Err(format!("下载的内容不是有效图片: {}", url)) } } @@ -158,8 +159,7 @@ pub struct IconInfo { /// 复制图标文件 #[tauri::command] pub fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult { - use std::fs; - use std::path::Path; + use std::{fs, path::Path}; let file_path = Path::new(&path); diff --git a/src-tauri/src/cmd/clash.rs b/src-tauri/src/cmd/clash.rs index ad1e8c61..8f61f0f9 100644 --- a/src-tauri/src/cmd/clash.rs +++ b/src-tauri/src/cmd/clash.rs @@ -24,7 +24,8 @@ pub async fn patch_clash_config(payload: Mapping) -> CmdResult { /// 修改Clash模式 #[tauri::command] pub async fn patch_clash_mode(payload: String) -> CmdResult { - Ok(feat::change_clash_mode(payload)) + feat::change_clash_mode(payload); + Ok(()) } /// 切换Clash核心 @@ -98,9 +99,11 @@ pub async fn save_dns_config(dns_config: Mapping) -> CmdResult { /// 应用或撤销DNS配置 #[tauri::command] pub fn apply_dns_config(apply: bool) -> CmdResult { - use crate::config::Config; - use crate::core::{handle, CoreManager}; - use crate::utils::dirs; + use crate::{ + config::Config, + core::{handle, CoreManager}, + utils::dirs, + }; use tauri::async_runtime; // 使用spawn来处理异步操作 diff --git a/src-tauri/src/cmd/mod.rs b/src-tauri/src/cmd/mod.rs index c4fd72cf..1ff5645e 100644 --- a/src-tauri/src/cmd/mod.rs +++ b/src-tauri/src/cmd/mod.rs @@ -4,29 +4,29 @@ use anyhow::Result; pub type CmdResult = Result; // Command modules -pub mod profile; -pub mod validate; -pub mod uwp; -pub mod webdav; pub mod app; -pub mod network; pub mod clash; -pub mod verge; +pub mod network; +pub mod profile; +pub mod proxy; pub mod runtime; pub mod save_profile; pub mod system; -pub mod proxy; +pub mod uwp; +pub mod validate; +pub mod verge; +pub mod webdav; // Re-export all command functions for backwards compatibility -pub use profile::*; -pub use validate::*; -pub use uwp::*; -pub use webdav::*; pub use app::*; -pub use network::*; pub use clash::*; -pub use verge::*; +pub use network::*; +pub use profile::*; +pub use proxy::*; pub use runtime::*; pub use save_profile::*; pub use system::*; -pub use proxy::*; \ No newline at end of file +pub use uwp::*; +pub use validate::*; +pub use verge::*; +pub use webdav::*; diff --git a/src-tauri/src/cmd/network.rs b/src-tauri/src/cmd/network.rs index d1db0cec..5bc17163 100644 --- a/src-tauri/src/cmd/network.rs +++ b/src-tauri/src/cmd/network.rs @@ -1,8 +1,8 @@ -use crate::wrap_err; use super::CmdResult; -use sysproxy::{Autoproxy, Sysproxy}; -use serde_yaml::Mapping; +use crate::wrap_err; use network_interface::NetworkInterface; +use serde_yaml::Mapping; +use sysproxy::{Autoproxy, Sysproxy}; /// get the system proxy #[tauri::command] @@ -46,8 +46,7 @@ pub fn get_network_interfaces() -> Vec { /// 获取网络接口详细信息 #[tauri::command] pub fn get_network_interfaces_info() -> CmdResult> { - use network_interface::NetworkInterface; - use network_interface::NetworkInterfaceConfig; + use network_interface::{NetworkInterface, NetworkInterfaceConfig}; let names = get_network_interfaces(); let interfaces = wrap_err!(NetworkInterface::show())?; diff --git a/src-tauri/src/cmd/profile.rs b/src-tauri/src/cmd/profile.rs index 00622d56..9537ef36 100644 --- a/src-tauri/src/cmd/profile.rs +++ b/src-tauri/src/cmd/profile.rs @@ -1,11 +1,11 @@ +use super::CmdResult; use crate::{ config::*, core::*, - feat, + feat, log_err, ret_err, utils::{dirs, help}, - log_err, ret_err, wrap_err, + wrap_err, }; -use super::CmdResult; /// 获取配置文件列表 #[tauri::command] @@ -31,7 +31,7 @@ pub async fn enhance_profiles() -> CmdResult { } Err(e) => { println!("[enhance_profiles] 更新过程发生错误: {}", e); - handle::Handle::notice_message("config_validate::process_terminated", &e.to_string()); + handle::Handle::notice_message("config_validate::process_terminated", e.to_string()); Ok(()) } } @@ -76,19 +76,17 @@ pub async fn delete_profile(index: String) -> CmdResult { /// 修改profiles的配置 #[tauri::command] -pub async fn patch_profiles_config( - profiles: IProfiles -) -> CmdResult { +pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult { println!("[cmd配置patch] 开始修改配置文件"); - + // 保存当前配置,以便在验证失败时恢复 let current_profile = Config::profiles().latest().current.clone(); println!("[cmd配置patch] 当前配置: {:?}", current_profile); - + // 更新profiles配置 println!("[cmd配置patch] 正在更新配置草稿"); wrap_err!({ Config::profiles().draft().patch_config(profiles) })?; - + // 更新配置并进行验证 match CoreManager::global().update_config().await { Ok((true, _)) => { @@ -102,7 +100,7 @@ pub async fn patch_profiles_config( Ok((false, error_msg)) => { println!("[cmd配置patch] 配置验证失败: {}", error_msg); Config::profiles().discard(); - + // 如果验证失败,恢复到之前的配置 if let Some(prev_profile) = current_profile { println!("[cmd配置patch] 尝试恢复到之前的配置: {}", prev_profile); @@ -124,7 +122,7 @@ pub async fn patch_profiles_config( Err(e) => { println!("[cmd配置patch] 更新过程发生错误: {}", e); Config::profiles().discard(); - handle::Handle::notice_message("config_validate::boot_error", &e.to_string()); + handle::Handle::notice_message("config_validate::boot_error", e.to_string()); Ok(false) } } @@ -134,9 +132,12 @@ pub async fn patch_profiles_config( #[tauri::command] pub async fn patch_profiles_config_by_profile_index( _app_handle: tauri::AppHandle, - profile_index: String + profile_index: String, ) -> CmdResult { - let profiles = IProfiles{current: Some(profile_index), items: None}; + let profiles = IProfiles { + current: Some(profile_index), + items: None, + }; patch_profiles_config(profiles).await } diff --git a/src-tauri/src/cmd/runtime.rs b/src-tauri/src/cmd/runtime.rs index 34e21c47..f3193e54 100644 --- a/src-tauri/src/cmd/runtime.rs +++ b/src-tauri/src/cmd/runtime.rs @@ -1,11 +1,8 @@ -use crate::{ - config::*, - wrap_err, -}; use super::CmdResult; +use crate::{config::*, wrap_err}; use anyhow::Context; -use std::collections::HashMap; use serde_yaml::Mapping; +use std::collections::HashMap; /// 获取运行时配置 #[tauri::command] diff --git a/src-tauri/src/cmd/save_profile.rs b/src-tauri/src/cmd/save_profile.rs index abece254..5c4b73ef 100644 --- a/src-tauri/src/cmd/save_profile.rs +++ b/src-tauri/src/cmd/save_profile.rs @@ -1,10 +1,5 @@ -use crate::{ - config::*, - core::*, - utils::dirs, - wrap_err, -}; use super::CmdResult; +use crate::{config::*, core::*, utils::dirs, wrap_err}; use std::fs; /// 保存profiles的配置 @@ -20,7 +15,7 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR let profiles_guard = profiles.latest(); let item = wrap_err!(profiles_guard.get_item(&index))?; // 确定是否为merge类型文件 - let is_merge = item.itype.as_ref().map_or(false, |t| t == "merge"); + let is_merge = item.itype.as_ref().is_some_and(|t| t == "merge"); let content = wrap_err!(item.read_file())?; let path = item.file.clone().ok_or("file field is null")?; let profiles_dir = wrap_err!(dirs::app_profiles_dir())?; @@ -29,14 +24,20 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR // 保存新的配置文件 wrap_err!(fs::write(&file_path, file_data.clone().unwrap()))?; - + let file_path_str = file_path.to_string_lossy().to_string(); - println!("[cmd配置save] 开始验证配置文件: {}, 是否为merge文件: {}", file_path_str, is_merge_file); - + println!( + "[cmd配置save] 开始验证配置文件: {}, 是否为merge文件: {}", + file_path_str, is_merge_file + ); + // 对于 merge 文件,只进行语法验证,不进行后续内核验证 if is_merge_file { println!("[cmd配置save] 检测到merge文件,只进行语法验证"); - match CoreManager::global().validate_config_file(&file_path_str, Some(true)).await { + match CoreManager::global() + .validate_config_file(&file_path_str, Some(true)) + .await + { Ok((true, _)) => { println!("[cmd配置save] merge文件语法验证通过"); // 成功后尝试更新整体配置 @@ -63,9 +64,12 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR } } } - + // 非merge文件使用完整验证流程 - match CoreManager::global().validate_config_file(&file_path_str, None).await { + match CoreManager::global() + .validate_config_file(&file_path_str, None) + .await + { Ok((true, _)) => { println!("[cmd配置save] 验证成功"); Ok(()) @@ -74,16 +78,17 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR println!("[cmd配置save] 验证失败: {}", error_msg); // 恢复原始配置文件 wrap_err!(fs::write(&file_path, original_content))?; - + // 智能判断错误类型 - let is_script_error = file_path_str.ends_with(".js") || - error_msg.contains("Script syntax error") || - error_msg.contains("Script must contain a main function") || - error_msg.contains("Failed to read script file"); - - if error_msg.contains("YAML syntax error") || - error_msg.contains("Failed to read file:") || - (!file_path_str.ends_with(".js") && !is_script_error) { + let is_script_error = file_path_str.ends_with(".js") + || error_msg.contains("Script syntax error") + || error_msg.contains("Script must contain a main function") + || error_msg.contains("Failed to read script file"); + + if error_msg.contains("YAML syntax error") + || error_msg.contains("Failed to read file:") + || (!file_path_str.ends_with(".js") && !is_script_error) + { // 普通YAML错误使用YAML通知处理 println!("[cmd配置save] YAML配置文件验证失败,发送通知"); let result = (false, error_msg.clone()); @@ -98,7 +103,7 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR println!("[cmd配置save] 其他类型验证失败,发送一般通知"); handle::Handle::notice_message("config_validate::error", &error_msg); } - + Ok(()) } Err(e) => { diff --git a/src-tauri/src/cmd/system.rs b/src-tauri/src/cmd/system.rs index 2ec266e0..e10d099a 100644 --- a/src-tauri/src/cmd/system.rs +++ b/src-tauri/src/cmd/system.rs @@ -1,8 +1,10 @@ use super::CmdResult; -use crate::core::handle; -use crate::module::sysinfo::PlatformSpecification; +use crate::{ + core::{self, handle, service, CoreManager}, + module::sysinfo::PlatformSpecification, + wrap_err, +}; use tauri_plugin_clipboard_manager::ClipboardExt; -use crate::{core::{self, CoreManager, service}, wrap_err}; #[tauri::command] pub async fn export_diagnostic_info() -> CmdResult<()> { @@ -11,8 +13,7 @@ pub async fn export_diagnostic_info() -> CmdResult<()> { let app_handle = handle::Handle::global().app_handle().unwrap(); let cliboard = app_handle.clipboard(); - - if let Err(_) = cliboard.write_text(info) { + if cliboard.write_text(info).is_err() { log::error!(target: "app", "Failed to write to clipboard"); } Ok(()) diff --git a/src-tauri/src/cmd/uwp.rs b/src-tauri/src/cmd/uwp.rs index 67db3055..28b88bd4 100644 --- a/src-tauri/src/cmd/uwp.rs +++ b/src-tauri/src/cmd/uwp.rs @@ -4,8 +4,7 @@ use super::CmdResult; #[cfg(windows)] mod platform { use super::CmdResult; - use crate::core::win_uwp; - use crate::wrap_err; + use crate::{core::win_uwp, wrap_err}; pub async fn invoke_uwp_tool() -> CmdResult { wrap_err!(win_uwp::invoke_uwptools().await) diff --git a/src-tauri/src/cmd/validate.rs b/src-tauri/src/cmd/validate.rs index 017dc1a2..94cab28b 100644 --- a/src-tauri/src/cmd/validate.rs +++ b/src-tauri/src/cmd/validate.rs @@ -1,5 +1,5 @@ -use crate::core::*; use super::CmdResult; +use crate::core::*; /// 发送脚本验证通知消息 #[tauri::command] @@ -13,7 +13,7 @@ pub async fn script_validate_notice(status: String, msg: String) -> CmdResult { pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str) { if !result.0 { let error_msg = &result.1; - + // 根据错误消息内容判断错误类型 let status = if error_msg.starts_with("File not found:") { "config_validate::file_not_found" @@ -27,7 +27,7 @@ pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str) // 如果是其他类型错误,作为一般脚本错误处理 "config_validate::script_error" }; - + log::warn!(target: "app", "{} 验证失败: {}", file_type, error_msg); handle::Handle::notice_message(status, error_msg); } @@ -37,12 +37,15 @@ pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str) #[tauri::command] pub async fn validate_script_file(file_path: String) -> CmdResult { log::info!(target: "app", "验证脚本文件: {}", file_path); - - match CoreManager::global().validate_config_file(&file_path, None).await { + + match CoreManager::global() + .validate_config_file(&file_path, None) + .await + { Ok(result) => { handle_script_validation_notice(&result, "脚本文件"); - Ok(result.0) // 返回验证结果布尔值 - }, + Ok(result.0) // 返回验证结果布尔值 + } Err(e) => { let error_msg = e.to_string(); log::error!(target: "app", "验证脚本文件过程发生错误: {}", error_msg); @@ -58,10 +61,10 @@ pub fn handle_yaml_validation_notice(result: &(bool, String), file_type: &str) { if !result.0 { let error_msg = &result.1; println!("[通知] 处理{}验证错误: {}", file_type, error_msg); - + // 检查是否为merge文件 let is_merge_file = file_type.contains("合并"); - + // 根据错误消息内容判断错误类型 let status = if error_msg.starts_with("File not found:") { "config_validate::file_not_found" @@ -93,7 +96,7 @@ pub fn handle_yaml_validation_notice(result: &(bool, String), file_type: &str) { "config_validate::yaml_error" } }; - + log::warn!(target: "app", "{} 验证失败: {}", file_type, error_msg); println!("[通知] 发送通知: status={}, msg={}", status, error_msg); handle::Handle::notice_message(status, error_msg); diff --git a/src-tauri/src/cmd/verge.rs b/src-tauri/src/cmd/verge.rs index d80e5e3d..7e8bc7a8 100644 --- a/src-tauri/src/cmd/verge.rs +++ b/src-tauri/src/cmd/verge.rs @@ -1,9 +1,5 @@ -use crate::{ - config::*, - feat, - wrap_err, -}; use super::CmdResult; +use crate::{config::*, feat, wrap_err}; /// 获取Verge配置 #[tauri::command] diff --git a/src-tauri/src/cmd/webdav.rs b/src-tauri/src/cmd/webdav.rs index ddd39a50..e4cd51d3 100644 --- a/src-tauri/src/cmd/webdav.rs +++ b/src-tauri/src/cmd/webdav.rs @@ -1,10 +1,5 @@ -use crate::{ - core, - config::*, - feat, - wrap_err, -}; use super::CmdResult; +use crate::{config::*, core, feat, wrap_err}; use reqwest_dav::list_cmd::ListFile; /// 保存 WebDAV 配置 diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index e58d8cc7..10c37b01 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -1,9 +1,9 @@ use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge}; use crate::{ config::PrfItem, + core::{handle, CoreManager}, enhance, utils::{dirs, help}, - core::{handle, CoreManager}, }; use anyhow::{anyhow, Result}; use once_cell::sync::OnceCell; @@ -73,14 +73,17 @@ impl Config { // 生成运行时配置文件并验证 let config_result = Self::generate_file(ConfigType::Run); - let validation_result = if let Ok(_) = config_result { + let validation_result = if config_result.is_ok() { // 验证配置文件 println!("[首次启动] 开始验证配置"); - + match CoreManager::global().validate_config().await { Ok((is_valid, error_msg)) => { if !is_valid { - println!("[首次启动] 配置验证失败,使用默认最小配置启动: {}", error_msg); + println!( + "[首次启动] 配置验证失败,使用默认最小配置启动: {}", + error_msg + ); CoreManager::global() .use_default_config("config_validate::boot_error", &error_msg) .await?; @@ -101,10 +104,7 @@ impl Config { } else { println!("[首次启动] 生成配置文件失败,使用默认配置"); CoreManager::global() - .use_default_config( - "config_validate::error", - "", - ) + .use_default_config("config_validate::error", "") .await?; Some(("config_validate::error", String::new())) }; diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs index 69b1b123..bbd76770 100644 --- a/src-tauri/src/config/mod.rs +++ b/src-tauri/src/config/mod.rs @@ -8,14 +8,9 @@ mod profiles; mod runtime; mod verge; -pub use self::clash::*; -pub use self::config::*; -pub use self::draft::*; -pub use self::encrypt::*; -pub use self::prfitem::*; -pub use self::profiles::*; -pub use self::runtime::*; -pub use self::verge::*; +pub use self::{ + clash::*, config::*, draft::*, encrypt::*, prfitem::*, profiles::*, runtime::*, verge::*, +}; pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) { return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;"; diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index c796e99f..101d17d2 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -234,10 +234,10 @@ impl PrfItem { option: Option, ) -> Result { let opt_ref = option.as_ref(); - let with_proxy = opt_ref.map_or(false, |o| o.with_proxy.unwrap_or(false)); - let self_proxy = opt_ref.map_or(false, |o| o.self_proxy.unwrap_or(false)); + let with_proxy = opt_ref.is_some_and(|o| o.with_proxy.unwrap_or(false)); + let self_proxy = opt_ref.is_some_and(|o| o.self_proxy.unwrap_or(false)); let accept_invalid_certs = - opt_ref.map_or(false, |o| o.danger_accept_invalid_certs.unwrap_or(false)); + opt_ref.is_some_and(|o| o.danger_accept_invalid_certs.unwrap_or(false)); let user_agent = opt_ref.and_then(|o| o.user_agent.clone()); let update_interval = opt_ref.and_then(|o| o.update_interval); let mut merge = opt_ref.and_then(|o| o.merge.clone()); diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index e7a2c897..1dd78dfd 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -472,15 +472,17 @@ impl IProfiles { /// 获取所有的profiles(uid,名称) pub fn all_profile_uid_and_name(&self) -> Option> { - match self.items.as_ref() { - Some(items) => Some(items.iter().filter_map(|e| { - if let (Some(uid), Some(name)) = (e.uid.clone(), e.name.clone()) { - Some((uid, name)) - } else { - None - } - }).collect()), - None => None, - } + self.items.as_ref().map(|items| { + items + .iter() + .filter_map(|e| { + if let (Some(uid), Some(name)) = (e.uid.clone(), e.name.clone()) { + Some((uid, name)) + } else { + None + } + }) + .collect() + }) } } diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index a266416e..e268cc54 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -1,7 +1,7 @@ -use crate::config::DEFAULT_PAC; -use crate::config::{deserialize_encrypted, serialize_encrypted}; -use crate::utils::i18n; -use crate::utils::{dirs, help}; +use crate::{ + config::{deserialize_encrypted, serialize_encrypted, DEFAULT_PAC}, + utils::{dirs, help, i18n}, +}; use anyhow::Result; use log::LevelFilter; use serde::{Deserialize, Serialize}; @@ -101,7 +101,7 @@ pub struct IVerge { /// hotkey map /// format: {func},{key} pub hotkeys: Option>, - + /// enable global hotkey pub enable_global_hotkey: Option, diff --git a/src-tauri/src/core/backup.rs b/src-tauri/src/core/backup.rs index dbba01a7..59cf9787 100644 --- a/src-tauri/src/core/backup.rs +++ b/src-tauri/src/core/backup.rs @@ -1,16 +1,17 @@ -use crate::config::Config; -use crate::utils::dirs; +use crate::{config::Config, utils::dirs}; use anyhow::Error; use once_cell::sync::OnceCell; use parking_lot::Mutex; use reqwest_dav::list_cmd::{ListEntity, ListFile}; -use std::collections::HashMap; -use std::env::{consts::OS, temp_dir}; -use std::fs; -use std::io::Write; -use std::path::PathBuf; -use std::sync::Arc; -use std::time::Duration; +use std::{ + collections::HashMap, + env::{consts::OS, temp_dir}, + fs, + io::Write, + path::PathBuf, + sync::Arc, + time::Duration, +}; use tokio::time::timeout; use zip::write::SimpleFileOptions; diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index 0204fd5c..d1a666ee 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -1,16 +1,17 @@ -use crate::config::*; #[cfg(target_os = "macos")] use crate::core::tray::Tray; -use crate::core::{handle, service}; -use crate::log_err; -use crate::module::mihomo::MihomoManager; -use crate::utils::{dirs, help}; +use crate::{ + config::*, + core::{handle, service}, + log_err, + module::mihomo::MihomoManager, + utils::{dirs, help}, +}; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; use std::{path::PathBuf, sync::Arc, time::Duration}; use tauri_plugin_shell::ShellExt; -use tokio::sync::Mutex; -use tokio::time::sleep; +use tokio::{sync::Mutex, time::sleep}; #[derive(Debug)] pub struct CoreManager { diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index 33050eec..bef15409 100755 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -1,13 +1,10 @@ -use crate::core::handle; -use crate::{config::Config, feat, log_err}; -use crate::utils::resolve; +use crate::{config::Config, core::handle, feat, log_err, utils::resolve}; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; use parking_lot::Mutex; use std::{collections::HashMap, sync::Arc}; -use tauri::Manager; +use tauri::{async_runtime, Manager}; use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, ShortcutState}; -use tauri::async_runtime; pub struct Hotkey { current: Arc>>, // 保存当前的热键设置 @@ -26,7 +23,10 @@ impl Hotkey { let verge = Config::verge(); let enable_global_hotkey = verge.latest().enable_global_hotkey.unwrap_or(true); - println!("Initializing hotkeys, global hotkey enabled: {}", enable_global_hotkey); + println!( + "Initializing hotkeys, global hotkey enabled: {}", + enable_global_hotkey + ); log::info!(target: "app", "Initializing hotkeys, global hotkey enabled: {}", enable_global_hotkey); // 如果全局热键被禁用,则不注册热键 @@ -85,11 +85,17 @@ impl Hotkey { let app_handle = handle::Handle::global().app_handle().unwrap(); let manager = app_handle.global_shortcut(); - println!("Attempting to register hotkey: {} for function: {}", hotkey, func); + println!( + "Attempting to register hotkey: {} for function: {}", + hotkey, func + ); log::info!(target: "app", "Attempting to register hotkey: {} for function: {}", hotkey, func); if manager.is_registered(hotkey) { - println!("Hotkey {} was already registered, unregistering first", hotkey); + println!( + "Hotkey {} was already registered, unregistering first", + hotkey + ); log::info!(target: "app", "Hotkey {} was already registered, unregistering first", hotkey); manager.unregister(hotkey)?; } @@ -101,12 +107,12 @@ impl Hotkey { || { println!("=== Hotkey Dashboard Window Operation Start ==="); log::info!(target: "app", "=== Hotkey Dashboard Window Operation Start ==="); - + // 使用 spawn_blocking 来确保在正确的线程上执行 async_runtime::spawn_blocking(|| { println!("Toggle dashboard window visibility"); log::info!(target: "app", "Toggle dashboard window visibility"); - + // 检查窗口是否存在 if let Some(window) = handle::Handle::global().get_window() { // 如果窗口可见,则隐藏它 @@ -131,11 +137,11 @@ impl Hotkey { resolve::create_window(); } }); - + println!("=== Hotkey Dashboard Window Operation End ==="); log::info!(target: "app", "=== Hotkey Dashboard Window Operation End ==="); } - }, + } "clash_mode_rule" => || feat::change_clash_mode("rule".into()), "clash_mode_global" => || feat::change_clash_mode("global".into()), "clash_mode_direct" => || feat::change_clash_mode("direct".into()), @@ -169,11 +175,14 @@ impl Hotkey { // 直接执行函数,不做任何状态检查 println!("Executing function directly"); log::info!(target: "app", "Executing function directly"); - + // 获取轻量模式状态和全局热键状态 let is_lite_mode = Config::verge().latest().enable_lite_mode.unwrap_or(false); - let is_enable_global_hotkey = Config::verge().latest().enable_global_hotkey.unwrap_or(true); - + let is_enable_global_hotkey = Config::verge() + .latest() + .enable_global_hotkey + .unwrap_or(true); + // 在轻量模式下或配置了全局热键时,始终执行热键功能 if is_lite_mode || is_enable_global_hotkey { f(); @@ -181,7 +190,7 @@ impl Hotkey { // 非轻量模式且未启用全局热键时,只在窗口可见且有焦点的情况下响应热键 let is_visible = window.is_visible().unwrap_or(false); let is_focused = window.is_focused().unwrap_or(false); - + if is_focused && is_visible { f(); } diff --git a/src-tauri/src/core/service.rs b/src-tauri/src/core/service.rs index 154bd4e0..10804b45 100644 --- a/src-tauri/src/core/service.rs +++ b/src-tauri/src/core/service.rs @@ -1,10 +1,7 @@ -use crate::config::Config; -use crate::utils::dirs; +use crate::{config::Config, utils::dirs}; use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::path::PathBuf; -use std::{env::current_exe, process::Command as StdCommand}; +use std::{collections::HashMap, env::current_exe, path::PathBuf, process::Command as StdCommand}; use tokio::time::Duration; // Windows only @@ -154,11 +151,13 @@ pub async fn reinstall_service() -> Result<()> { let install_shell: String = install_path.to_string_lossy().into_owned(); let uninstall_shell: String = uninstall_path.to_string_lossy().into_owned(); - + // 获取提示文本,如果 i18n 失败则使用硬编码默认值 let prompt = crate::utils::i18n::t("Service Administrator Prompt"); let prompt = if prompt == "Service Administrator Prompt" { - if Config::verge().latest().language.as_deref() == Some("zh") || Config::verge().latest().language.is_none() { + if Config::verge().latest().language.as_deref() == Some("zh") + || Config::verge().latest().language.is_none() + { "Clash Verge 需要使用管理员权限来重新安装系统服务" } else { "Clash Verge needs administrator privileges to reinstall the system service" @@ -166,7 +165,7 @@ pub async fn reinstall_service() -> Result<()> { } else { &prompt }; - + let command = format!( r#"do shell script "sudo '{uninstall_shell}' && sudo '{install_shell}'" with administrator privileges with prompt "{prompt}""# ); diff --git a/src-tauri/src/core/sysopt.rs b/src-tauri/src/core/sysopt.rs index e7fbc3a5..492fc53f 100644 --- a/src-tauri/src/core/sysopt.rs +++ b/src-tauri/src/core/sysopt.rs @@ -1,6 +1,6 @@ -use crate::core::handle::Handle; use crate::{ config::{Config, IVerge}, + core::handle::Handle, log_err, }; use anyhow::Result; @@ -126,8 +126,7 @@ impl Sysopt { if !sys_enable { return self.reset_sysproxy().await; } - use crate::core::handle::Handle; - use crate::utils::dirs; + use crate::{core::handle::Handle, utils::dirs}; use anyhow::bail; use tauri_plugin_shell::ShellExt; @@ -185,8 +184,7 @@ impl Sysopt { #[cfg(target_os = "windows")] { - use crate::core::handle::Handle; - use crate::utils::dirs; + use crate::{core::handle::Handle, utils::dirs}; use anyhow::bail; use tauri_plugin_shell::ShellExt; @@ -305,8 +303,7 @@ impl Sysopt { #[cfg(target_os = "windows")] { - use crate::core::handle::Handle; - use crate::utils::dirs; + use crate::{core::handle::Handle, utils::dirs}; use tauri_plugin_shell::ShellExt; let app_handle = Handle::global().app_handle().unwrap(); diff --git a/src-tauri/src/core/timer.rs b/src-tauri/src/core/timer.rs index d5ad7436..1b5d0aeb 100644 --- a/src-tauri/src/core/timer.rs +++ b/src-tauri/src/core/timer.rs @@ -1,12 +1,9 @@ -use crate::config::Config; -use crate::feat; -use crate::core::CoreManager; +use crate::{config::Config, core::CoreManager, feat}; use anyhow::{Context, Result}; use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder}; use once_cell::sync::OnceCell; use parking_lot::Mutex; -use std::collections::HashMap; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; type TaskID = u64; @@ -195,16 +192,14 @@ impl Timer { log::info!(target: "app", "Running timer task `{}`", uid); match feat::update_profile(uid.clone(), None).await { - Ok(_) => { - match CoreManager::global().update_config().await { - Ok(_) => { - log::info!(target: "app", "Timer task completed successfully for uid: {}", uid); - } - Err(e) => { - log::error!(target: "app", "Timer task refresh error for uid {}: {}", uid, e); - } + Ok(_) => match CoreManager::global().update_config().await { + Ok(_) => { + log::info!(target: "app", "Timer task completed successfully for uid: {}", uid); } - } + Err(e) => { + log::error!(target: "app", "Timer task refresh error for uid {}: {}", uid, e); + } + }, Err(e) => { log::error!(target: "app", "Timer task update error for uid {}: {}", uid, e); } diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index d0f99da9..ba87d8b9 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -134,7 +134,7 @@ impl Tray { let profile_uid_and_name = Config::profiles() .data() .all_profile_uid_and_name() - .unwrap_or(Vec::new()); + .unwrap_or_default(); let tray = app_handle.tray_by_id("main").unwrap(); let _ = tray.set_menu(Some(create_tray_menu( @@ -408,8 +408,8 @@ fn create_tray_menu( .is_current_profile_index(profile_uid.to_string()); CheckMenuItem::with_id( app_handle, - &format!("profiles_{}", profile_uid), - t(&profile_name), + format!("profiles_{}", profile_uid), + t(profile_name), true, is_current_profile, None::<&str>, diff --git a/src-tauri/src/core/tray/speed_rate.rs b/src-tauri/src/core/tray/speed_rate.rs index d0dc4755..b3beb30c 100644 --- a/src-tauri/src/core/tray/speed_rate.rs +++ b/src-tauri/src/core/tray/speed_rate.rs @@ -1,16 +1,15 @@ -use crate::module::mihomo::Rate; -use crate::module::mihomo::MihomoManager; -use crate::utils::help::format_bytes_speed; +use crate::{ + module::mihomo::{MihomoManager, Rate}, + utils::help::format_bytes_speed, +}; use ab_glyph::FontArc; use anyhow::Result; use futures::Stream; use image::{GenericImageView, Rgba, RgbaImage}; use imageproc::drawing::draw_text_mut; use parking_lot::Mutex; -use std::io::Cursor; -use std::sync::Arc; -use tokio_tungstenite::tungstenite::http; -use tokio_tungstenite::tungstenite::Message; +use std::{io::Cursor, sync::Arc}; +use tokio_tungstenite::tungstenite::{http, Message}; use tungstenite::client::IntoClientRequest; #[derive(Debug, Clone)] pub struct SpeedRate { diff --git a/src-tauri/src/crate_mihomo_api/src/lib.rs b/src-tauri/src/crate_mihomo_api/src/lib.rs index 13578df6..8f18da8d 100644 --- a/src-tauri/src/crate_mihomo_api/src/lib.rs +++ b/src-tauri/src/crate_mihomo_api/src/lib.rs @@ -15,7 +15,7 @@ impl MihomoManager { proxies: serde_json::Value::Null, providers_proxies: serde_json::Value::Null, })), - headers: headers, + headers, } } @@ -76,7 +76,7 @@ impl MihomoManager { client_response.text().await.map(|text| json!(text)) } .map_err(|e| e.to_string())?; - return Ok(response); + Ok(response) } pub async fn refresh_proxies(&self) -> Result<&Self, String> { @@ -129,6 +129,6 @@ impl MihomoManager { self.mihomo_server, name, test_url, timeout ); let response = self.send_request("GET", url, None).await?; - return Ok(response); + Ok(response) } } diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index 607e9fd7..c3f5f50b 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -5,17 +5,10 @@ mod script; pub mod seq; mod tun; -use self::chain::*; -use self::field::*; -use self::merge::*; -use self::script::*; -use self::seq::*; -use self::tun::*; -use crate::config::Config; -use crate::utils::tmpl; +use self::{chain::*, field::*, merge::*, script::*, seq::*, tun::*}; +use crate::{config::Config, utils::tmpl}; use serde_yaml::Mapping; -use std::collections::HashMap; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; type ResultLog = Vec<(String, String)>; @@ -267,11 +260,11 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) { if enable_dns_settings { use crate::utils::dirs; use std::fs; - + // 尝试读取dns_config.yaml if let Ok(app_dir) = dirs::app_home_dir() { let dns_path = app_dir.join("dns_config.yaml"); - + if dns_path.exists() { if let Ok(dns_yaml) = fs::read_to_string(&dns_path) { if let Ok(dns_config) = serde_yaml::from_str::(&dns_yaml) { diff --git a/src-tauri/src/enhance/seq.rs b/src-tauri/src/enhance/seq.rs index 82672c93..950a30b6 100644 --- a/src-tauri/src/enhance/seq.rs +++ b/src-tauri/src/enhance/seq.rs @@ -108,7 +108,7 @@ proxy-groups: - "proxy1" "#; let mut config: Mapping = serde_yaml::from_str(config_str).unwrap(); - + let seq = SeqMap { prepend: Sequence::new(), append: Sequence::new(), @@ -121,16 +121,32 @@ proxy-groups: let proxies = config.get("proxies").unwrap().as_sequence().unwrap(); assert_eq!(proxies.len(), 1); assert_eq!( - proxies[0].as_mapping().unwrap().get("name").unwrap().as_str().unwrap(), + proxies[0] + .as_mapping() + .unwrap() + .get("name") + .unwrap() + .as_str() + .unwrap(), "proxy2" ); // Check if proxy1 is removed from all groups let groups = config.get("proxy-groups").unwrap().as_sequence().unwrap(); - let group1_proxies = groups[0].as_mapping().unwrap() - .get("proxies").unwrap().as_sequence().unwrap(); - let group2_proxies = groups[1].as_mapping().unwrap() - .get("proxies").unwrap().as_sequence().unwrap(); + let group1_proxies = groups[0] + .as_mapping() + .unwrap() + .get("proxies") + .unwrap() + .as_sequence() + .unwrap(); + let group2_proxies = groups[1] + .as_mapping() + .unwrap() + .get("proxies") + .unwrap() + .as_sequence() + .unwrap(); assert_eq!(group1_proxies.len(), 1); assert_eq!(group1_proxies[0].as_str().unwrap(), "proxy2"); diff --git a/src-tauri/src/enhance/tun.rs b/src-tauri/src/enhance/tun.rs index 0af2e885..3e06b0c7 100644 --- a/src-tauri/src/enhance/tun.rs +++ b/src-tauri/src/enhance/tun.rs @@ -24,7 +24,7 @@ pub async fn use_tun(mut config: Mapping, enable: bool) -> Mapping { let mut tun_val = tun_val.map_or(Mapping::new(), |val| { val.as_mapping().cloned().unwrap_or(Mapping::new()) }); - + if enable { // 读取DNS配置 let dns_key = Value::from("dns"); @@ -40,20 +40,20 @@ pub async fn use_tun(mut config: Mapping, enable: bool) -> Mapping { // 检查现有的 enhanced-mode 设置 let current_mode = dns_val - .get(&Value::from("enhanced-mode")) + .get(Value::from("enhanced-mode")) .and_then(|v| v.as_str()) .unwrap_or("fake-ip"); // 只有当 enhanced-mode 是 fake-ip 或未设置时才修改 DNS 配置 - if current_mode == "fake-ip" || !dns_val.contains_key(&Value::from("enhanced-mode")) { + if current_mode == "fake-ip" || !dns_val.contains_key(Value::from("enhanced-mode")) { revise!(dns_val, "enable", true); revise!(dns_val, "ipv6", ipv6_val); - - if !dns_val.contains_key(&Value::from("enhanced-mode")) { + + if !dns_val.contains_key(Value::from("enhanced-mode")) { revise!(dns_val, "enhanced-mode", "fake-ip"); } - - if !dns_val.contains_key(&Value::from("fake-ip-range")) { + + if !dns_val.contains_key(Value::from("fake-ip-range")) { revise!(dns_val, "fake-ip-range", "198.18.0.1/16"); } @@ -63,7 +63,7 @@ pub async fn use_tun(mut config: Mapping, enable: bool) -> Mapping { crate::utils::resolve::set_public_dns("223.6.6.6".to_string()).await; } } - + // 当TUN启用时,将修改后的DNS配置写回 revise!(config, "dns", dns_val); } else { @@ -75,6 +75,6 @@ pub async fn use_tun(mut config: Mapping, enable: bool) -> Mapping { // 更新TUN配置 revise!(tun_val, "enable", enable); revise!(config, "tun", tun_val); - + config } diff --git a/src-tauri/src/feat/backup.rs b/src-tauri/src/feat/backup.rs index 3f069c1c..fa3dd968 100644 --- a/src-tauri/src/feat/backup.rs +++ b/src-tauri/src/feat/backup.rs @@ -1,7 +1,9 @@ -use crate::config::{Config, IVerge}; -use crate::core::backup; -use crate::log_err; -use crate::utils::dirs::app_home_dir; +use crate::{ + config::{Config, IVerge}, + core::backup, + log_err, + utils::dirs::app_home_dir, +}; use anyhow::Result; use reqwest_dav::list_cmd::ListFile; use std::fs; diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index 13a1914a..a43dee67 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -1,8 +1,10 @@ -use crate::config::Config; -use crate::core::{handle, tray, CoreManager}; -use crate::log_err; -use crate::module::mihomo::MihomoManager; -use crate::utils::resolve; +use crate::{ + config::Config, + core::{handle, tray, CoreManager}, + log_err, + module::mihomo::MihomoManager, + utils::resolve, +}; use serde_yaml::{Mapping, Value}; use tauri::Manager; diff --git a/src-tauri/src/feat/config.rs b/src-tauri/src/feat/config.rs index 0a236463..db8c2557 100644 --- a/src-tauri/src/feat/config.rs +++ b/src-tauri/src/feat/config.rs @@ -1,7 +1,9 @@ -use crate::config::{Config, IVerge}; -use crate::core::{handle, hotkey, sysopt, tray, CoreManager}; -use crate::log_err; -use crate::utils::resolve; +use crate::{ + config::{Config, IVerge}, + core::{handle, hotkey, sysopt, tray, CoreManager}, + log_err, + utils::resolve, +}; use anyhow::Result; use serde_yaml::Mapping; use tauri::Manager; diff --git a/src-tauri/src/feat/profile.rs b/src-tauri/src/feat/profile.rs index 9b2d6613..b552dfef 100644 --- a/src-tauri/src/feat/profile.rs +++ b/src-tauri/src/feat/profile.rs @@ -1,8 +1,8 @@ -use crate::cmd; -use crate::config::{Config, PrfItem, PrfOption}; -use crate::core::handle; -use crate::core::CoreManager; -use crate::core::*; +use crate::{ + cmd, + config::{Config, PrfItem, PrfOption}, + core::{handle, CoreManager, *}, +}; use anyhow::{bail, Result}; /// Toggle proxy profile @@ -29,7 +29,7 @@ pub async fn update_profile(uid: String, option: Option) -> Result<() let profiles = Config::profiles(); let profiles = profiles.latest(); let item = profiles.get_item(&uid)?; - let is_remote = item.itype.as_ref().map_or(false, |s| s == "remote"); + let is_remote = item.itype.as_ref().is_some_and(|s| s == "remote"); if !is_remote { println!("[订阅更新] {} 不是远程订阅,跳过更新", uid); diff --git a/src-tauri/src/feat/proxy.rs b/src-tauri/src/feat/proxy.rs index 39f7e38e..dc1d28ea 100644 --- a/src-tauri/src/feat/proxy.rs +++ b/src-tauri/src/feat/proxy.rs @@ -1,6 +1,7 @@ -use crate::config::Config; -use crate::config::IVerge; -use crate::core::handle; +use crate::{ + config::{Config, IVerge}, + core::handle, +}; use std::env; use tauri_plugin_clipboard_manager::ClipboardExt; @@ -72,10 +73,16 @@ pub fn copy_clash_env() { }; let export_text = match env_type.as_str() { - "bash" => format!("export https_proxy={http_proxy} http_proxy={http_proxy} all_proxy={socks5_proxy}"), + "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}\" }}"), + "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}"), _ => { log::error!(target: "app", "copy_clash_env: Invalid env type! {env_type}"); @@ -83,7 +90,7 @@ pub fn copy_clash_env() { } }; - if let Err(_) = cliboard.write_text(export_text) { + if cliboard.write_text(export_text).is_err() { log::error!(target: "app", "Failed to write to clipboard"); } } diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs index 4ba60d75..253c1f71 100644 --- a/src-tauri/src/feat/window.rs +++ b/src-tauri/src/feat/window.rs @@ -1,9 +1,9 @@ -use crate::config::Config; -use crate::core::handle; -use crate::core::{sysopt, CoreManager}; -use crate::module::mihomo::MihomoManager; -use crate::utils::resolve; -use futures; +use crate::{ + config::Config, + core::{handle, sysopt, CoreManager}, + module::mihomo::MihomoManager, + utils::resolve, +}; use tauri::Manager; use tauri_plugin_window_state::{AppHandleExt, StateFlags}; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index ae40966c..0a10e135 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3,17 +3,19 @@ mod config; mod core; mod enhance; mod feat; -mod utils; mod module; -use crate::core::hotkey; -use crate::utils::{resolve, resolve::resolve_scheme, server}; +mod utils; +use crate::{ + core::hotkey, + utils::{resolve, resolve::resolve_scheme, server}, +}; use config::Config; -use tauri_plugin_autostart::MacosLauncher; -use tauri_plugin_deep_link::DeepLinkExt; use std::sync::{Mutex, Once}; use tauri::AppHandle; #[cfg(target_os = "macos")] use tauri::Manager; +use tauri_plugin_autostart::MacosLauncher; +use tauri_plugin_deep_link::DeepLinkExt; /// A global singleton handle to the application. pub struct AppHandleManager { @@ -57,7 +59,7 @@ impl AppHandleManager { let _ = app_handle.set_activation_policy(tauri::ActivationPolicy::Regular); } } - + pub fn set_activation_policy_accessory(&self) { #[cfg(target_os = "macos")] { @@ -66,7 +68,7 @@ impl AppHandleManager { let _ = app_handle.set_activation_policy(tauri::ActivationPolicy::Accessory); } } - + pub fn set_activation_policy_prohibited(&self) { #[cfg(target_os = "macos")] { @@ -77,6 +79,7 @@ impl AppHandleManager { } } +#[allow(clippy::panic)] pub fn run() { // 单例检测 let app_exists: bool = tauri::async_runtime::block_on(async move { @@ -219,12 +222,18 @@ pub fn run() { AppHandleManager::global().init(app_handle.clone()); #[cfg(target_os = "macos")] { - let main_window = AppHandleManager::global().get_handle().get_webview_window("main").unwrap(); + let main_window = AppHandleManager::global() + .get_handle() + .get_webview_window("main") + .unwrap(); let _ = main_window.set_title("Clash Verge"); } } #[cfg(target_os = "macos")] - tauri::RunEvent::Reopen { has_visible_windows, .. } => { + tauri::RunEvent::Reopen { + has_visible_windows, + .. + } => { if !has_visible_windows { AppHandleManager::global().set_activation_policy_regular(); } @@ -259,8 +268,11 @@ pub fn run() { { log_err!(hotkey::Hotkey::global().register("Control+Q", "quit")); }; - { - let is_enable_global_hotkey = Config::verge().latest().enable_global_hotkey.unwrap_or(true); + { + let is_enable_global_hotkey = Config::verge() + .latest() + .enable_global_hotkey + .unwrap_or(true); if !is_enable_global_hotkey { log_err!(hotkey::Hotkey::global().init()) } @@ -275,8 +287,11 @@ pub fn run() { { log_err!(hotkey::Hotkey::global().unregister("Control+Q")); }; - { - let is_enable_global_hotkey = Config::verge().latest().enable_global_hotkey.unwrap_or(true); + { + let is_enable_global_hotkey = Config::verge() + .latest() + .enable_global_hotkey + .unwrap_or(true); if !is_enable_global_hotkey { log_err!(hotkey::Hotkey::global().reset()) } diff --git a/src-tauri/src/module/mihomo.rs b/src-tauri/src/module/mihomo.rs index 67dd0d00..47929b92 100644 --- a/src-tauri/src/module/mihomo.rs +++ b/src-tauri/src/module/mihomo.rs @@ -65,6 +65,6 @@ impl MihomoManager { .unwrap() .to_string(); let token = http::header::HeaderValue::from_str(&auth).unwrap(); - return (ws_url, token); + (ws_url, token) } } diff --git a/src-tauri/src/module/mod.rs b/src-tauri/src/module/mod.rs index 9b6f1f38..c07cdce0 100644 --- a/src-tauri/src/module/mod.rs +++ b/src-tauri/src/module/mod.rs @@ -1,2 +1,2 @@ +pub mod mihomo; pub mod sysinfo; -pub mod mihomo; \ No newline at end of file diff --git a/src-tauri/src/module/sysinfo.rs b/src-tauri/src/module/sysinfo.rs index 54e0b5bc..d22132b0 100644 --- a/src-tauri/src/module/sysinfo.rs +++ b/src-tauri/src/module/sysinfo.rs @@ -43,7 +43,6 @@ impl PlatformSpecification { }) }); - Self { system_name, system_version, diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs index 5c5d2b84..72b70a2c 100644 --- a/src-tauri/src/utils/dirs.rs +++ b/src-tauri/src/utils/dirs.rs @@ -1,8 +1,7 @@ use crate::core::handle; use anyhow::Result; use once_cell::sync::OnceCell; -use std::fs; -use std::path::PathBuf; +use std::{fs, path::PathBuf}; use tauri::Manager; #[cfg(not(feature = "verge-dev"))] diff --git a/src-tauri/src/utils/help.rs b/src-tauri/src/utils/help.rs index adb9b69c..c6a1ad2f 100644 --- a/src-tauri/src/utils/help.rs +++ b/src-tauri/src/utils/help.rs @@ -207,7 +207,7 @@ macro_rules! t { /// # Examples /// ```not_run /// format_bytes_speed(1000) // returns "1000B/s" -/// format_bytes_speed(1024) // returns "1.0KB/s" +/// format_bytes_speed(1024) // returns "1.0KB/s" /// format_bytes_speed(1024 * 1024) // returns "1.0MB/s" /// ``` /// ``` diff --git a/src-tauri/src/utils/i18n.rs b/src-tauri/src/utils/i18n.rs index 088c0ac4..96898735 100644 --- a/src-tauri/src/utils/i18n.rs +++ b/src-tauri/src/utils/i18n.rs @@ -1,5 +1,4 @@ -use crate::config::Config; -use crate::utils::dirs; +use crate::{config::Config, utils::dirs}; use once_cell::sync::Lazy; use serde_json::Value; use std::{collections::HashMap, fs, path::PathBuf}; diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index 91d18e60..06593572 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -1,16 +1,21 @@ -use crate::config::*; -use crate::core::handle; -use crate::utils::{dirs, help}; +use crate::{ + config::*, + core::handle, + utils::{dirs, help}, +}; use anyhow::Result; use chrono::{Local, TimeZone}; use log::LevelFilter; -use log4rs::append::console::ConsoleAppender; -use log4rs::append::file::FileAppender; -use log4rs::config::{Appender, Logger, Root}; -use log4rs::encode::pattern::PatternEncoder; -use std::fs::{self, DirEntry}; -use std::path::PathBuf; -use std::str::FromStr; +use log4rs::{ + append::{console::ConsoleAppender, file::FileAppender}, + config::{Appender, Logger, Root}, + encode::pattern::PatternEncoder, +}; +use std::{ + fs::{self, DirEntry}, + path::PathBuf, + str::FromStr, +}; use tauri_plugin_shell::ShellExt; /// initialize this instance's log file @@ -142,69 +147,106 @@ fn init_dns_config() -> Result<()> { ("enable".into(), Value::Bool(true)), ("listen".into(), Value::String(":53".into())), ("enhanced-mode".into(), Value::String("fake-ip".into())), - ("fake-ip-range".into(), Value::String("198.18.0.1/16".into())), - ("fake-ip-filter-mode".into(), Value::String("blacklist".into())), + ( + "fake-ip-range".into(), + Value::String("198.18.0.1/16".into()), + ), + ( + "fake-ip-filter-mode".into(), + Value::String("blacklist".into()), + ), ("prefer-h3".into(), Value::Bool(false)), ("respect-rules".into(), Value::Bool(false)), ("use-hosts".into(), Value::Bool(false)), ("use-system-hosts".into(), Value::Bool(false)), - ("fake-ip-filter".into(), Value::Sequence(vec![ - Value::String("*.lan".into()), - Value::String("*.local".into()), - Value::String("*.arpa".into()), - Value::String("time.*.com".into()), - Value::String("ntp.*.com".into()), - Value::String("time.*.com".into()), - Value::String("+.market.xiaomi.com".into()), - Value::String("localhost.ptlogin2.qq.com".into()), - Value::String("*.msftncsi.com".into()), - Value::String("www.msftconnecttest.com".into()), - ])), - ("default-nameserver".into(), Value::Sequence(vec![ - Value::String("223.6.6.6".into()), - Value::String("8.8.8.8".into()), - ])), - ("nameserver".into(), Value::Sequence(vec![ - Value::String("8.8.8.8".into()), - Value::String("https://doh.pub/dns-query".into()), - Value::String("https://dns.alidns.com/dns-query".into()), - ])), - ("fallback".into(), Value::Sequence(vec![ - Value::String("https://dns.alidns.com/dns-query".into()), - Value::String("https://dns.google/dns-query".into()), - Value::String("https://cloudflare-dns.com/dns-query".into()), - ])), - ("nameserver-policy".into(), Value::Mapping(serde_yaml::Mapping::new())), - ("proxy-server-nameserver".into(), Value::Sequence(vec![ - Value::String("https://doh.pub/dns-query".into()), - Value::String("https://dns.alidns.com/dns-query".into()), - ])), + ( + "fake-ip-filter".into(), + Value::Sequence(vec![ + Value::String("*.lan".into()), + Value::String("*.local".into()), + Value::String("*.arpa".into()), + Value::String("time.*.com".into()), + Value::String("ntp.*.com".into()), + Value::String("time.*.com".into()), + Value::String("+.market.xiaomi.com".into()), + Value::String("localhost.ptlogin2.qq.com".into()), + Value::String("*.msftncsi.com".into()), + Value::String("www.msftconnecttest.com".into()), + ]), + ), + ( + "default-nameserver".into(), + Value::Sequence(vec![ + Value::String("223.6.6.6".into()), + Value::String("8.8.8.8".into()), + ]), + ), + ( + "nameserver".into(), + Value::Sequence(vec![ + Value::String("8.8.8.8".into()), + Value::String("https://doh.pub/dns-query".into()), + Value::String("https://dns.alidns.com/dns-query".into()), + ]), + ), + ( + "fallback".into(), + Value::Sequence(vec![ + Value::String("https://dns.alidns.com/dns-query".into()), + Value::String("https://dns.google/dns-query".into()), + Value::String("https://cloudflare-dns.com/dns-query".into()), + ]), + ), + ( + "nameserver-policy".into(), + Value::Mapping(serde_yaml::Mapping::new()), + ), + ( + "proxy-server-nameserver".into(), + Value::Sequence(vec![ + Value::String("https://doh.pub/dns-query".into()), + Value::String("https://dns.alidns.com/dns-query".into()), + ]), + ), ("direct-nameserver".into(), Value::Sequence(vec![])), ("direct-nameserver-follow-policy".into(), Value::Bool(false)), - ("fallback-filter".into(), Value::Mapping(serde_yaml::Mapping::from_iter([ - ("geoip".into(), Value::Bool(true)), - ("geoip-code".into(), Value::String("CN".into())), - ("ipcidr".into(), Value::Sequence(vec![ - Value::String("240.0.0.0/4".into()), - Value::String("0.0.0.0/32".into()), + ( + "fallback-filter".into(), + Value::Mapping(serde_yaml::Mapping::from_iter([ + ("geoip".into(), Value::Bool(true)), + ("geoip-code".into(), Value::String("CN".into())), + ( + "ipcidr".into(), + Value::Sequence(vec![ + Value::String("240.0.0.0/4".into()), + Value::String("0.0.0.0/32".into()), + ]), + ), + ( + "domain".into(), + Value::Sequence(vec![ + Value::String("+.google.com".into()), + Value::String("+.facebook.com".into()), + Value::String("+.youtube.com".into()), + ]), + ), ])), - ("domain".into(), Value::Sequence(vec![ - Value::String("+.google.com".into()), - Value::String("+.facebook.com".into()), - Value::String("+.youtube.com".into()), - ])), - ]))), + ), ]); // 检查DNS配置文件是否存在 let app_dir = dirs::app_home_dir()?; let dns_path = app_dir.join("dns_config.yaml"); - + if !dns_path.exists() { log::info!(target: "app", "Creating default DNS config file"); - help::save_yaml(&dns_path, &default_dns_config, Some("# Clash Verge DNS Config"))?; + help::save_yaml( + &dns_path, + &default_dns_config, + Some("# Clash Verge DNS Config"), + )?; } - + Ok(()) } @@ -323,8 +365,7 @@ pub fn init_resources() -> Result<()> { #[cfg(target_os = "windows")] pub fn init_scheme() -> Result<()> { use tauri::utils::platform::current_exe; - use winreg::enums::*; - use winreg::RegKey; + use winreg::{enums::*, RegKey}; let app_exe = current_exe()?; let app_exe = dunce::canonicalize(app_exe)?; diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs index 4b5ce6fb..4cf03d3e 100644 --- a/src-tauri/src/utils/mod.rs +++ b/src-tauri/src/utils/mod.rs @@ -1,8 +1,8 @@ pub mod dirs; pub mod error; pub mod help; +pub mod i18n; pub mod init; pub mod resolve; pub mod server; pub mod tmpl; -pub mod i18n; diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index b12955f0..97124f0a 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -1,9 +1,12 @@ -use crate::config::IVerge; -use crate::utils::error; -use crate::{config::Config, config::PrfItem, core::*, utils::init, utils::server}; -use crate::{log_err, wrap_err}; #[cfg(target_os = "macos")] use crate::AppHandleManager; +use crate::{ + config::{Config, IVerge, PrfItem}, + core::*, + log_err, + utils::{error, init, server}, + wrap_err, +}; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; use percent_encoding::percent_decode_str; @@ -201,7 +204,7 @@ pub fn create_window() { log::info!(target: "app", "Window created successfully, attempting to show"); let _ = window.show(); let _ = window.set_focus(); - + // 设置窗口状态监控,实时保存窗口位置和大小 crate::feat::setup_window_state_monitor(&app_handle); } @@ -315,8 +318,7 @@ fn resolve_random_port_config() -> Result<()> { #[cfg(target_os = "macos")] pub async fn set_public_dns(dns_server: String) { - use crate::core::handle; - use crate::utils::dirs; + use crate::{core::handle, utils::dirs}; use tauri_plugin_shell::ShellExt; let app_handle = handle::Handle::global().app_handle().unwrap(); @@ -352,8 +354,7 @@ pub async fn set_public_dns(dns_server: String) { #[cfg(target_os = "macos")] pub async fn restore_public_dns() { - use crate::core::handle; - use crate::utils::dirs; + use crate::{core::handle, utils::dirs}; use tauri_plugin_shell::ShellExt; let app_handle = handle::Handle::global().app_handle().unwrap(); log::info!(target: "app", "try to unset system dns"); diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs index 2f2b20bb..1baee60b 100644 --- a/src-tauri/src/utils/server.rs +++ b/src-tauri/src/utils/server.rs @@ -1,8 +1,10 @@ extern crate warp; use super::resolve; -use crate::config::{Config, IVerge, DEFAULT_PAC}; -use crate::log_err; +use crate::{ + config::{Config, IVerge, DEFAULT_PAC}, + log_err, +}; use anyhow::{bail, Result}; use port_scanner::local_port_available; use std::convert::Infallible; diff --git a/vite.config.mts b/vite.config.mts index 9fb9b95c..0f85ebd9 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -39,7 +39,7 @@ export default defineConfig({ }), ], build: { - outDir: "../dist", + outDir: "dist", emptyOutDir: true, }, resolve: {