edition 2024 (#4702)

* feat: update Cargo.toml for 2024 edition and optimize release profiles

* feat: refactor environment variable settings for Linux and improve code organization

* Refactor conditional statements to use `&&` for improved readability

- Updated multiple files to combine nested `if let` statements using `&&` for better clarity and conciseness.
- This change enhances the readability of the code by reducing indentation levels and making the conditions more straightforward.
- Affected files include: media_unlock_checker.rs, profile.rs, clash.rs, profiles.rs, async_proxy_query.rs, core.rs, handle.rs, hotkey.rs, service.rs, timer.rs, tray/mod.rs, merge.rs, seq.rs, config.rs, proxy.rs, window.rs, general.rs, dirs.rs, i18n.rs, init.rs, network.rs, and window.rs in the resolve module.

* refactor: streamline conditional checks using `&&` for improved readability

* fix: update release profile settings for panic behavior and optimization

* fix: adjust optimization level in Cargo.toml and reorder imports in lightweight.rs
This commit is contained in:
Tunglies
2025-09-10 09:49:06 +08:00
committed by GitHub
parent ccbffa14f0
commit 251678493c
51 changed files with 772 additions and 784 deletions

View File

@@ -6,7 +6,7 @@ authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
license = "GPL-3.0-only" license = "GPL-3.0-only"
repository = "https://github.com/clash-verge-rev/clash-verge-rev.git" repository = "https://github.com/clash-verge-rev/clash-verge-rev.git"
default-run = "clash-verge" default-run = "clash-verge"
edition = "2021" edition = "2024"
build = "build.rs" build = "build.rs"
[package.metadata.bundle] [package.metadata.bundle]
@@ -118,26 +118,32 @@ tokio-trace = ["console-subscriber"]
[profile.release] [profile.release]
panic = "abort" panic = "abort"
codegen-units = 1 codegen-units = 16
lto = true lto = true
opt-level = "s" opt-level = 2
debug = false
strip = true strip = true
overflow-checks = false
rpath = false
[profile.dev] [profile.dev]
incremental = true incremental = true
codegen-units = 256 # 增加编译单元,提升编译速度 codegen-units = 64
opt-level = 0 # 禁用优化,进一步提升编译速度 opt-level = 0
debug = true # 保留调试信息 debug = true
strip = false # 不剥离符号,保留调试信息 strip = "none"
overflow-checks = true
lto = false
rpath = false
[profile.fast-release] [profile.fast-release]
inherits = "release" # 继承 release 的配置 inherits = "release"
panic = "abort" # 与 release 相同 panic = "abort"
codegen-units = 256 # 增加编译单元,提升编译速度 codegen-units = 64
lto = false # 禁用 LTO提升编译速度 lto = false
opt-level = 0 # 禁用优化,大幅提升编译速度 opt-level = 0
debug = true # 保留调试信息 debug = true
strip = false # 不剥离符号,保留调试信息 strip = false
[lib] [lib]
name = "app_lib" name = "app_lib"

View File

@@ -1,4 +1,4 @@
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::{Criterion, criterion_group, criterion_main};
use std::hint::black_box; use std::hint::black_box;
// 业务模型 & Draft // 业务模型 & Draft

View File

@@ -1,7 +1,7 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
config::Config, config::Config,
core::{handle, CoreManager}, core::{CoreManager, handle},
}; };
use crate::{ use crate::{
config::*, config::*,
@@ -166,7 +166,7 @@ pub async fn save_dns_config(dns_config: Mapping) -> CmdResult {
pub async fn apply_dns_config(apply: bool) -> CmdResult { pub async fn apply_dns_config(apply: bool) -> CmdResult {
use crate::{ use crate::{
config::Config, config::Config,
core::{handle, CoreManager}, core::{CoreManager, handle},
utils::dirs, utils::dirs,
}; };

View File

@@ -618,20 +618,20 @@ async fn check_netflix(client: &Client) -> UnlockItem {
{ {
Ok(response) => { Ok(response) => {
// 检查重定向位置 // 检查重定向位置
if let Some(location) = response.headers().get("location") { if let Some(location) = response.headers().get("location")
if let Ok(location_str) = location.to_str() { && let Ok(location_str) = location.to_str()
// 解析位置获取区域 {
let parts: Vec<&str> = location_str.split('/').collect(); // 解析位置获取区域
if parts.len() >= 4 { let parts: Vec<&str> = location_str.split('/').collect();
let region_code = parts[3].split('-').next().unwrap_or("unknown"); if parts.len() >= 4 {
let emoji = country_code_to_emoji(region_code); let region_code = parts[3].split('-').next().unwrap_or("unknown");
return UnlockItem { let emoji = country_code_to_emoji(region_code);
name: "Netflix".to_string(), return UnlockItem {
status: "Yes".to_string(), name: "Netflix".to_string(),
region: Some(format!("{emoji}{region_code}")), status: "Yes".to_string(),
check_time: Some(get_local_date_string()), region: Some(format!("{emoji}{region_code}")),
}; check_time: Some(get_local_date_string()),
} };
} }
} }
// 如果没有重定向,假设是美国 // 如果没有重定向,假设是美国
@@ -691,22 +691,18 @@ async fn check_netflix_cdn(client: &Client) -> UnlockItem {
match response.json::<serde_json::Value>().await { match response.json::<serde_json::Value>().await {
Ok(data) => { Ok(data) => {
// 尝试从数据中提取区域信息 // 尝试从数据中提取区域信息
if let Some(targets) = data.get("targets").and_then(|t| t.as_array()) { if let Some(targets) = data.get("targets").and_then(|t| t.as_array())
if !targets.is_empty() { && !targets.is_empty()
if let Some(location) = targets[0].get("location") { && let Some(location) = targets[0].get("location")
if let Some(country) = && let Some(country) = location.get("country").and_then(|c| c.as_str())
location.get("country").and_then(|c| c.as_str()) {
{ let emoji = country_code_to_emoji(country);
let emoji = country_code_to_emoji(country); return UnlockItem {
return UnlockItem { name: "Netflix".to_string(),
name: "Netflix".to_string(), status: "Yes".to_string(),
status: "Yes".to_string(), region: Some(format!("{emoji}{country}")),
region: Some(format!("{emoji}{country}")), check_time: Some(get_local_date_string()),
check_time: Some(get_local_date_string()), };
};
}
}
}
} }
// 如果无法解析区域信息 // 如果无法解析区域信息

View File

@@ -1,5 +1,5 @@
use super::CmdResult; use super::CmdResult;
use crate::core::{async_proxy_query::AsyncProxyQuery, EventDrivenProxyManager}; use crate::core::{EventDrivenProxyManager, async_proxy_query::AsyncProxyQuery};
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::wrap_err; use crate::wrap_err;
use network_interface::NetworkInterface; use network_interface::NetworkInterface;

View File

@@ -1,13 +1,14 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
config::{ config::{
Config, IProfiles, PrfItem, PrfOption,
profiles::{ profiles::{
profiles_append_item_with_filedata_safe, profiles_delete_item_safe, profiles_append_item_with_filedata_safe, profiles_delete_item_safe,
profiles_patch_item_safe, profiles_reorder_safe, profiles_save_file_safe, profiles_patch_item_safe, profiles_reorder_safe, profiles_save_file_safe,
}, },
profiles_append_item_safe, Config, IProfiles, PrfItem, PrfOption, profiles_append_item_safe,
}, },
core::{handle, timer::Timer, tray::Tray, CoreManager}, core::{CoreManager, handle, timer::Timer, tray::Tray},
feat, logging, feat, logging,
process::AsyncHandler, process::AsyncHandler,
ret_err, ret_err,
@@ -290,109 +291,106 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile); logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile);
// 如果要切换配置,先检查目标配置文件是否有语法错误 // 如果要切换配置,先检查目标配置文件是否有语法错误
if let Some(new_profile) = profiles.current.as_ref() { if let Some(new_profile) = profiles.current.as_ref()
if current_profile.as_ref() != Some(new_profile) { && current_profile.as_ref() != Some(new_profile)
logging!(info, Type::Cmd, true, "正在切换到新配置: {}", new_profile); {
logging!(info, Type::Cmd, true, "正在切换到新配置: {}", new_profile);
// 获取目标配置文件路径 // 获取目标配置文件路径
let config_file_result = { let config_file_result = {
let profiles_config = Config::profiles().await; let profiles_config = Config::profiles().await;
let profiles_data = profiles_config.latest_ref(); let profiles_data = profiles_config.latest_ref();
match profiles_data.get_item(new_profile) { match profiles_data.get_item(new_profile) {
Ok(item) => { Ok(item) => {
if let Some(file) = &item.file { if let Some(file) = &item.file {
let path = dirs::app_profiles_dir().map(|dir| dir.join(file)); let path = dirs::app_profiles_dir().map(|dir| dir.join(file));
path.ok() path.ok()
} else { } else {
None
}
}
Err(e) => {
logging!(error, Type::Cmd, true, "获取目标配置信息失败: {}", e);
None None
} }
} }
}; Err(e) => {
logging!(error, Type::Cmd, true, "获取目标配置信息失败: {}", e);
// 如果获取到文件路径检查YAML语法 None
if let Some(file_path) = config_file_result {
if !file_path.exists() {
logging!(
error,
Type::Cmd,
true,
"目标配置文件不存在: {}",
file_path.display()
);
handle::Handle::notice_message(
"config_validate::file_not_found",
format!("{}", file_path.display()),
);
return Ok(false);
} }
}
};
// 超时保护 // 如果获取到文件路径检查YAML语法
let file_read_result = tokio::time::timeout( if let Some(file_path) = config_file_result {
Duration::from_secs(5), if !file_path.exists() {
tokio::fs::read_to_string(&file_path), logging!(
) error,
.await; Type::Cmd,
true,
"目标配置文件不存在: {}",
file_path.display()
);
handle::Handle::notice_message(
"config_validate::file_not_found",
format!("{}", file_path.display()),
);
return Ok(false);
}
match file_read_result { // 超时保护
Ok(Ok(content)) => { let file_read_result = tokio::time::timeout(
let yaml_parse_result = AsyncHandler::spawn_blocking(move || { Duration::from_secs(5),
serde_yaml_ng::from_str::<serde_yaml_ng::Value>(&content) tokio::fs::read_to_string(&file_path),
}) )
.await; .await;
match yaml_parse_result { match file_read_result {
Ok(Ok(_)) => { Ok(Ok(content)) => {
logging!(info, Type::Cmd, true, "目标配置文件语法正确"); let yaml_parse_result = AsyncHandler::spawn_blocking(move || {
} serde_yaml_ng::from_str::<serde_yaml_ng::Value>(&content)
Ok(Err(err)) => { })
let error_msg = format!(" {err}"); .await;
logging!(
error, match yaml_parse_result {
Type::Cmd, Ok(Ok(_)) => {
true, logging!(info, Type::Cmd, true, "目标配置文件语法正确");
"目标配置文件存在YAML语法错误:{}", }
error_msg Ok(Err(err)) => {
); let error_msg = format!(" {err}");
handle::Handle::notice_message( logging!(
"config_validate::yaml_syntax_error", error,
&error_msg, Type::Cmd,
); true,
return Ok(false); "目标配置文件存在YAML语法错误:{}",
} error_msg
Err(join_err) => { );
let error_msg = format!("YAML解析任务失败: {join_err}"); handle::Handle::notice_message(
logging!(error, Type::Cmd, true, "{}", error_msg); "config_validate::yaml_syntax_error",
handle::Handle::notice_message( &error_msg,
"config_validate::yaml_parse_error", );
&error_msg, return Ok(false);
); }
return Ok(false); Err(join_err) => {
} let error_msg = format!("YAML解析任务失败: {join_err}");
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message(
"config_validate::yaml_parse_error",
&error_msg,
);
return Ok(false);
} }
} }
Ok(Err(err)) => { }
let error_msg = format!("无法读取目标配置文件: {err}"); Ok(Err(err)) => {
logging!(error, Type::Cmd, true, "{}", error_msg); let error_msg = format!("无法读取目标配置文件: {err}");
handle::Handle::notice_message( logging!(error, Type::Cmd, true, "{}", error_msg);
"config_validate::file_read_error", handle::Handle::notice_message("config_validate::file_read_error", &error_msg);
&error_msg, return Ok(false);
); }
return Ok(false); Err(_) => {
} let error_msg = "读取配置文件超时(5秒)".to_string();
Err(_) => { logging!(error, Type::Cmd, true, "{}", error_msg);
let error_msg = "读取配置文件超时(5秒)".to_string(); handle::Handle::notice_message(
logging!(error, Type::Cmd, true, "{}", error_msg); "config_validate::file_read_timeout",
handle::Handle::notice_message( &error_msg,
"config_validate::file_read_timeout", );
&error_msg, return Ok(false);
);
return Ok(false);
}
} }
} }
} }
@@ -663,8 +661,9 @@ pub async fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
#[tauri::command] #[tauri::command]
pub async fn view_profile(index: String) -> CmdResult { pub async fn view_profile(index: String) -> CmdResult {
let profiles = Config::profiles().await; let profiles = Config::profiles().await;
let profiles_ref = profiles.latest_ref();
let file = { let file = {
wrap_err!(profiles.latest_ref().get_item(&index))? wrap_err!(profiles_ref.get_item(&index))?
.file .file
.clone() .clone()
.ok_or("the file field is null") .ok_or("the file field is null")

View File

@@ -16,11 +16,12 @@ pub async fn get_runtime_yaml() -> CmdResult<String> {
let runtime = Config::runtime().await; let runtime = Config::runtime().await;
let runtime = runtime.latest_ref(); let runtime = runtime.latest_ref();
let config = runtime.config.as_ref(); let config = runtime.config.as_ref();
wrap_err!(config wrap_err!(
.ok_or(anyhow::anyhow!("failed to parse config to yaml file")) config
.and_then( .ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|config| serde_yaml_ng::to_string(config).context("failed to convert config to yaml") .and_then(|config| serde_yaml_ng::to_string(config)
)) .context("failed to convert config to yaml"))
)
} }
/// 获取运行时存在的键 /// 获取运行时存在的键

View File

@@ -1,6 +1,6 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
core::{service, CoreManager}, core::{CoreManager, service},
utils::i18n::t, utils::i18n::t,
}; };
use anyhow::Result; use anyhow::Result;

View File

@@ -1,6 +1,6 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
core::{handle, CoreManager}, core::{CoreManager, handle},
logging, logging,
module::sysinfo::PlatformSpecification, module::sysinfo::PlatformSpecification,
utils::logging::Type, utils::logging::Type,

View File

@@ -25,17 +25,17 @@ impl IClashTemp {
match map_result { match map_result {
Ok(mut map) => { Ok(mut map) => {
template.0.keys().for_each(|key| { template.0.keys().for_each(|key| {
if !map.contains_key(key) { if !map.contains_key(key)
if let Some(value) = template.0.get(key) { && let Some(value) = template.0.get(key)
map.insert(key.clone(), value.clone()); {
} map.insert(key.clone(), value.clone());
} }
}); });
// 确保 secret 字段存在且不为空 // 确保 secret 字段存在且不为空
if let Some(Value::String(s)) = map.get_mut("secret") { if let Some(Value::String(s)) = map.get_mut("secret")
if s.is_empty() { && s.is_empty()
*s = "set-your-secret".to_string(); {
} *s = "set-your-secret".to_string();
} }
Self(Self::guard(map)) Self(Self::guard(map))
} }

View File

@@ -1,14 +1,14 @@
use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge}; use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
use crate::{ use crate::{
config::{profiles_append_item_safe, PrfItem}, config::{PrfItem, profiles_append_item_safe},
core::{handle, CoreManager}, core::{CoreManager, handle},
enhance, logging, enhance, logging,
utils::{dirs, help, logging::Type}, utils::{dirs, help, logging::Type},
}; };
use anyhow::{anyhow, Result}; use anyhow::{Result, anyhow};
use std::path::PathBuf; use std::path::PathBuf;
use tokio::sync::OnceCell; use tokio::sync::OnceCell;
use tokio::time::{sleep, Duration}; use tokio::time::{Duration, sleep};
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml"; pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml"; pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";

View File

@@ -1,9 +1,9 @@
use crate::utils::dirs::get_encryption_key; use crate::utils::dirs::get_encryption_key;
use aes_gcm::{ use aes_gcm::{
aead::{Aead, KeyInit},
Aes256Gcm, Key, Aes256Gcm, Key,
aead::{Aead, KeyInit},
}; };
use base64::{engine::general_purpose::STANDARD, Engine}; use base64::{Engine, engine::general_purpose::STANDARD};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
const NONCE_LENGTH: usize = 12; const NONCE_LENGTH: usize = 12;

View File

@@ -3,7 +3,7 @@ use crate::utils::{
network::{NetworkManager, ProxyType}, network::{NetworkManager, ProxyType},
tmpl, tmpl,
}; };
use anyhow::{bail, Context, Result}; use anyhow::{Context, Result, bail};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml_ng::Mapping; use serde_yaml_ng::Mapping;
use std::{fs, time::Duration}; use std::{fs, time::Duration};

View File

@@ -1,10 +1,10 @@
use super::{prfitem::PrfItem, PrfOption}; use super::{PrfOption, prfitem::PrfItem};
use crate::{ use crate::{
logging_error, logging_error,
process::AsyncHandler, process::AsyncHandler,
utils::{dirs, help, logging::Type}, utils::{dirs, help, logging::Type},
}; };
use anyhow::{bail, Context, Result}; use anyhow::{Context, Result, bail};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml_ng::Mapping; use serde_yaml_ng::Mapping;
use std::collections::HashSet; use std::collections::HashSet;
@@ -88,12 +88,12 @@ impl IProfiles {
self.items = Some(vec![]); self.items = Some(vec![]);
} }
if let Some(current) = patch.current { if let Some(current) = patch.current
if let Some(items) = self.items.as_ref() { && let Some(items) = self.items.as_ref()
let some_uid = Some(current); {
if items.iter().any(|e| e.uid == some_uid) { let some_uid = Some(current);
self.current = some_uid; if items.iter().any(|e| e.uid == some_uid) {
} self.current = some_uid;
} }
} }
@@ -287,24 +287,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = index { if let Some(index) = index
if let Some(file) = items.remove(index).file { && let Some(file) = items.remove(index).file
let _ = dirs::app_profiles_dir().map(async move |path| { {
let path = path.join(file); let _ = dirs::app_profiles_dir().map(async move |path| {
if path.exists() { let path = path.join(file);
let result = fs::remove_file(path.clone()).await; if path.exists() {
if let Err(err) = result { let result = fs::remove_file(path.clone()).await;
logging_error!( if let Err(err) = result {
Type::Config, logging_error!(
false, Type::Config,
"[配置文件删除] 删除文件 {} 失败: {}", false,
path.display(), "[配置文件删除] 删除文件 {} 失败: {}",
err path.display(),
); err
} );
} }
}); }
} });
} }
// get the merge index // get the merge index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -313,24 +313,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = merge_index { if let Some(index) = merge_index
if let Some(file) = items.remove(index).file { && let Some(file) = items.remove(index).file
let _ = dirs::app_profiles_dir().map(async move |path| { {
let path = path.join(file); let _ = dirs::app_profiles_dir().map(async move |path| {
if path.exists() { let path = path.join(file);
let result = fs::remove_file(path.clone()).await; if path.exists() {
if let Err(err) = result { let result = fs::remove_file(path.clone()).await;
logging_error!( if let Err(err) = result {
Type::Config, logging_error!(
false, Type::Config,
"[配置文件删除] 删除文件 {} 失败: {}", false,
path.display(), "[配置文件删除] 删除文件 {} 失败: {}",
err path.display(),
); err
} );
} }
}); }
} });
} }
// get the script index // get the script index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -339,24 +339,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = script_index { if let Some(index) = script_index
if let Some(file) = items.remove(index).file { && let Some(file) = items.remove(index).file
let _ = dirs::app_profiles_dir().map(async move |path| { {
let path = path.join(file); let _ = dirs::app_profiles_dir().map(async move |path| {
if path.exists() { let path = path.join(file);
let result = fs::remove_file(path.clone()).await; if path.exists() {
if let Err(err) = result { let result = fs::remove_file(path.clone()).await;
logging_error!( if let Err(err) = result {
Type::Config, logging_error!(
false, Type::Config,
"[配置文件删除] 删除文件 {} 失败: {}", false,
path.display(), "[配置文件删除] 删除文件 {} 失败: {}",
err path.display(),
); err
} );
} }
}); }
} });
} }
// get the rules index // get the rules index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -365,24 +365,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = rules_index { if let Some(index) = rules_index
if let Some(file) = items.remove(index).file { && let Some(file) = items.remove(index).file
let _ = dirs::app_profiles_dir().map(async move |path| { {
let path = path.join(file); let _ = dirs::app_profiles_dir().map(async move |path| {
if path.exists() { let path = path.join(file);
let result = fs::remove_file(path.clone()).await; if path.exists() {
if let Err(err) = result { let result = fs::remove_file(path.clone()).await;
logging_error!( if let Err(err) = result {
Type::Config, logging_error!(
false, Type::Config,
"[配置文件删除] 删除文件 {} 失败: {}", false,
path.display(), "[配置文件删除] 删除文件 {} 失败: {}",
err path.display(),
); err
} );
} }
}); }
} });
} }
// get the proxies index // get the proxies index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -391,24 +391,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = proxies_index { if let Some(index) = proxies_index
if let Some(file) = items.remove(index).file { && let Some(file) = items.remove(index).file
let _ = dirs::app_profiles_dir().map(async move |path| { {
let path = path.join(file); let _ = dirs::app_profiles_dir().map(async move |path| {
if path.exists() { let path = path.join(file);
let result = fs::remove_file(path.clone()).await; if path.exists() {
if let Err(err) = result { let result = fs::remove_file(path.clone()).await;
logging_error!( if let Err(err) = result {
Type::Config, logging_error!(
false, Type::Config,
"[配置文件删除] 删除文件 {} 失败: {}", false,
path.display(), "[配置文件删除] 删除文件 {} 失败: {}",
err path.display(),
); err
} );
} }
}); }
} });
} }
// get the groups index // get the groups index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -417,24 +417,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = groups_index { if let Some(index) = groups_index
if let Some(file) = items.remove(index).file { && let Some(file) = items.remove(index).file
let _ = dirs::app_profiles_dir().map(async move |path| { {
let path = path.join(file); let _ = dirs::app_profiles_dir().map(async move |path| {
if path.exists() { let path = path.join(file);
let result = fs::remove_file(path.clone()).await; if path.exists() {
if let Err(err) = result { let result = fs::remove_file(path.clone()).await;
logging_error!( if let Err(err) = result {
Type::Config, logging_error!(
false, Type::Config,
"[配置文件删除] 删除文件 {} 失败: {}", false,
path.display(), "[配置文件删除] 删除文件 {} 失败: {}",
err path.display(),
); err
} );
} }
}); }
} });
} }
// delete the original uid // delete the original uid
if current == uid { if current == uid {
@@ -595,25 +595,25 @@ impl IProfiles {
total_files += 1; total_files += 1;
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) { if let Some(file_name) = path.file_name().and_then(|n| n.to_str())
if Self::is_profile_file(file_name) { && Self::is_profile_file(file_name)
// 检查是否为全局扩展文件 {
if protected_files.contains(file_name) { // 检查是否为全局扩展文件
log::debug!(target: "app", "保护全局扩展配置文件: {file_name}"); if protected_files.contains(file_name) {
continue; log::debug!(target: "app", "保护全局扩展配置文件: {file_name}");
} continue;
}
// 检查是否为活跃文件 // 检查是否为活跃文件
if !active_files.contains(file_name) { if !active_files.contains(file_name) {
match std::fs::remove_file(&path) { match std::fs::remove_file(&path) {
Ok(_) => { Ok(_) => {
deleted_files.push(file_name.to_string()); deleted_files.push(file_name.to_string());
log::info!(target: "app", "已清理冗余文件: {file_name}"); log::info!(target: "app", "已清理冗余文件: {file_name}");
} }
Err(e) => { Err(e) => {
failed_deletions.push(format!("{file_name}: {e}")); failed_deletions.push(format!("{file_name}: {e}"));
log::warn!(target: "app", "清理文件失败: {file_name} - {e}"); log::warn!(target: "app", "清理文件失败: {file_name} - {e}");
}
} }
} }
} }
@@ -659,50 +659,44 @@ impl IProfiles {
} }
// 对于主 profile 类型remote/local还需要收集其关联的扩展文件 // 对于主 profile 类型remote/local还需要收集其关联的扩展文件
if let Some(itype) = &item.itype { if let Some(itype) = &item.itype
if itype == "remote" || itype == "local" { && (itype == "remote" || itype == "local")
if let Some(option) = &item.option { && let Some(option) = &item.option
// 收集关联的扩展文件 {
if let Some(merge_uid) = &option.merge { // 收集关联的扩展文件
if let Ok(merge_item) = self.get_item(merge_uid) { if let Some(merge_uid) = &option.merge
if let Some(file) = &merge_item.file { && let Ok(merge_item) = self.get_item(merge_uid)
active_files.insert(file.clone()); && let Some(file) = &merge_item.file
} {
} active_files.insert(file.clone());
} }
if let Some(script_uid) = &option.script { if let Some(script_uid) = &option.script
if let Ok(script_item) = self.get_item(script_uid) { && let Ok(script_item) = self.get_item(script_uid)
if let Some(file) = &script_item.file { && let Some(file) = &script_item.file
active_files.insert(file.clone()); {
} active_files.insert(file.clone());
} }
}
if let Some(rules_uid) = &option.rules { if let Some(rules_uid) = &option.rules
if let Ok(rules_item) = self.get_item(rules_uid) { && let Ok(rules_item) = self.get_item(rules_uid)
if let Some(file) = &rules_item.file { && let Some(file) = &rules_item.file
active_files.insert(file.clone()); {
} active_files.insert(file.clone());
} }
}
if let Some(proxies_uid) = &option.proxies { if let Some(proxies_uid) = &option.proxies
if let Ok(proxies_item) = self.get_item(proxies_uid) { && let Ok(proxies_item) = self.get_item(proxies_uid)
if let Some(file) = &proxies_item.file { && let Some(file) = &proxies_item.file
active_files.insert(file.clone()); {
} active_files.insert(file.clone());
} }
}
if let Some(groups_uid) = &option.groups { if let Some(groups_uid) = &option.groups
if let Ok(groups_item) = self.get_item(groups_uid) { && let Ok(groups_item) = self.get_item(groups_uid)
if let Some(file) = &groups_item.file { && let Some(file) = &groups_item.file
active_files.insert(file.clone()); {
} active_files.insert(file.clone());
}
}
}
} }
} }
} }

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
config::{deserialize_encrypted, serialize_encrypted, DEFAULT_PAC}, config::{DEFAULT_PAC, deserialize_encrypted, serialize_encrypted},
logging, logging,
utils::{dirs, help, i18n, logging::Type}, utils::{dirs, help, i18n, logging::Type},
}; };

View File

@@ -2,7 +2,7 @@
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use anyhow::Result; use anyhow::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::time::{timeout, Duration}; use tokio::time::{Duration, timeout};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use anyhow::anyhow; use anyhow::anyhow;
@@ -87,7 +87,7 @@ impl AsyncProxyQuery {
use std::ptr; use std::ptr;
use winapi::shared::minwindef::{DWORD, HKEY}; use winapi::shared::minwindef::{DWORD, HKEY};
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ}; use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
use winapi::um::winreg::{RegCloseKey, RegOpenKeyExW, RegQueryValueExW, HKEY_CURRENT_USER}; use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW};
unsafe { unsafe {
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0" let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
@@ -209,13 +209,13 @@ impl AsyncProxyQuery {
// Linux: 检查环境变量和GNOME设置 // Linux: 检查环境变量和GNOME设置
// 首先检查环境变量 // 首先检查环境变量
if let Ok(auto_proxy) = std::env::var("auto_proxy") { if let Ok(auto_proxy) = std::env::var("auto_proxy")
if !auto_proxy.is_empty() { && !auto_proxy.is_empty()
return Ok(AsyncAutoproxy { {
enable: true, return Ok(AsyncAutoproxy {
url: auto_proxy, enable: true,
}); url: auto_proxy,
} });
} }
// 尝试使用 gsettings 获取 GNOME 代理设置 // 尝试使用 gsettings 获取 GNOME 代理设置
@@ -224,31 +224,31 @@ impl AsyncProxyQuery {
.output() .output()
.await; .await;
if let Ok(output) = output { if let Ok(output) = output
if output.status.success() { && output.status.success()
let mode = String::from_utf8_lossy(&output.stdout).trim().to_string(); {
if mode.contains("auto") { let mode = String::from_utf8_lossy(&output.stdout).trim().to_string();
// 获取 PAC URL if mode.contains("auto") {
let pac_output = Command::new("gsettings") // 获取 PAC URL
.args(["get", "org.gnome.system.proxy", "autoconfig-url"]) let pac_output = Command::new("gsettings")
.output() .args(["get", "org.gnome.system.proxy", "autoconfig-url"])
.await; .output()
.await;
if let Ok(pac_output) = pac_output { if let Ok(pac_output) = pac_output
if pac_output.status.success() { && pac_output.status.success()
let pac_url = String::from_utf8_lossy(&pac_output.stdout) {
.trim() let pac_url = String::from_utf8_lossy(&pac_output.stdout)
.trim_matches('\'') .trim()
.trim_matches('"') .trim_matches('\'')
.to_string(); .trim_matches('"')
.to_string();
if !pac_url.is_empty() { if !pac_url.is_empty() {
return Ok(AsyncAutoproxy { return Ok(AsyncAutoproxy {
enable: true, enable: true,
url: pac_url, url: pac_url,
}); });
}
}
} }
} }
} }
@@ -271,7 +271,7 @@ impl AsyncProxyQuery {
use std::ptr; use std::ptr;
use winapi::shared::minwindef::{DWORD, HKEY}; use winapi::shared::minwindef::{DWORD, HKEY};
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ}; use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
use winapi::um::winreg::{RegCloseKey, RegOpenKeyExW, RegQueryValueExW, HKEY_CURRENT_USER}; use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW};
unsafe { unsafe {
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0" let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
@@ -402,10 +402,10 @@ impl AsyncProxyQuery {
http_host = host_part.trim().to_string(); http_host = host_part.trim().to_string();
} }
} else if line.contains("HTTPPort") { } else if line.contains("HTTPPort") {
if let Some(port_part) = line.split(':').nth(1) { if let Some(port_part) = line.split(':').nth(1)
if let Ok(port) = port_part.trim().parse::<u16>() { && let Ok(port) = port_part.trim().parse::<u16>()
http_port = port; {
} http_port = port;
} }
} else if line.contains("ExceptionsList") { } else if line.contains("ExceptionsList") {
// 解析异常列表 // 解析异常列表
@@ -431,16 +431,16 @@ impl AsyncProxyQuery {
// Linux: 检查环境变量和桌面环境设置 // Linux: 检查环境变量和桌面环境设置
// 首先检查环境变量 // 首先检查环境变量
if let Ok(http_proxy) = std::env::var("http_proxy") { if let Ok(http_proxy) = std::env::var("http_proxy")
if let Ok(proxy_info) = Self::parse_proxy_url(&http_proxy) { && let Ok(proxy_info) = Self::parse_proxy_url(&http_proxy)
return Ok(proxy_info); {
} return Ok(proxy_info);
} }
if let Ok(https_proxy) = std::env::var("https_proxy") { if let Ok(https_proxy) = std::env::var("https_proxy")
if let Ok(proxy_info) = Self::parse_proxy_url(&https_proxy) { && let Ok(proxy_info) = Self::parse_proxy_url(&https_proxy)
return Ok(proxy_info); {
} return Ok(proxy_info);
} }
// 尝试使用 gsettings 获取 GNOME 代理设置 // 尝试使用 gsettings 获取 GNOME 代理设置
@@ -449,45 +449,46 @@ impl AsyncProxyQuery {
.output() .output()
.await; .await;
if let Ok(mode_output) = mode_output { if let Ok(mode_output) = mode_output
if mode_output.status.success() { && mode_output.status.success()
let mode = String::from_utf8_lossy(&mode_output.stdout) {
.trim() let mode = String::from_utf8_lossy(&mode_output.stdout)
.to_string(); .trim()
if mode.contains("manual") { .to_string();
// 获取HTTP代理设置 if mode.contains("manual") {
let host_result = Command::new("gsettings") // 获取HTTP代理设置
.args(["get", "org.gnome.system.proxy.http", "host"]) let host_result = Command::new("gsettings")
.output() .args(["get", "org.gnome.system.proxy.http", "host"])
.await; .output()
.await;
let port_result = Command::new("gsettings") let port_result = Command::new("gsettings")
.args(["get", "org.gnome.system.proxy.http", "port"]) .args(["get", "org.gnome.system.proxy.http", "port"])
.output() .output()
.await; .await;
if let (Ok(host_output), Ok(port_output)) = (host_result, port_result) { if let (Ok(host_output), Ok(port_output)) = (host_result, port_result)
if host_output.status.success() && port_output.status.success() { && host_output.status.success()
let host = String::from_utf8_lossy(&host_output.stdout) && port_output.status.success()
.trim() {
.trim_matches('\'') let host = String::from_utf8_lossy(&host_output.stdout)
.trim_matches('"') .trim()
.to_string(); .trim_matches('\'')
.trim_matches('"')
.to_string();
let port = String::from_utf8_lossy(&port_output.stdout) let port = String::from_utf8_lossy(&port_output.stdout)
.trim() .trim()
.parse::<u16>() .parse::<u16>()
.unwrap_or(8080); .unwrap_or(8080);
if !host.is_empty() { if !host.is_empty() {
return Ok(AsyncSysproxy { return Ok(AsyncSysproxy {
enable: true, enable: true,
host, host,
port, port,
bypass: String::new(), bypass: String::new(),
}); });
}
}
} }
} }
} }

View File

@@ -19,12 +19,12 @@ use chrono::Local;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{ use std::{
fmt, fmt,
fs::{create_dir_all, File}, fs::{File, create_dir_all},
io::Write, io::Write,
path::PathBuf, path::PathBuf,
sync::Arc, sync::Arc,
}; };
use tauri_plugin_shell::{process::CommandChild, ShellExt}; use tauri_plugin_shell::{ShellExt, process::CommandChild};
#[derive(Debug)] #[derive(Debug)]
pub struct CoreManager { pub struct CoreManager {
@@ -467,18 +467,18 @@ impl CoreManager {
Ok((pids, process_name)) => { Ok((pids, process_name)) => {
for pid in pids { for pid in pids {
// 跳过当前管理的进程 // 跳过当前管理的进程
if let Some(current) = current_pid { if let Some(current) = current_pid
if pid == current { && pid == current
logging!( {
debug, logging!(
Type::Core, debug,
true, Type::Core,
"跳过当前管理的进程: {} (PID: {})", true,
process_name, "跳过当前管理的进程: {} (PID: {})",
pid process_name,
); pid
continue; );
} continue;
} }
pids_to_kill.push((pid, process_name.clone())); pids_to_kill.push((pid, process_name.clone()));
} }
@@ -527,7 +527,7 @@ impl CoreManager {
use std::mem; use std::mem;
use winapi::um::handleapi::CloseHandle; use winapi::um::handleapi::CloseHandle;
use winapi::um::tlhelp32::{ use winapi::um::tlhelp32::{
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W, CreateToolhelp32Snapshot, PROCESSENTRY32W, Process32FirstW, Process32NextW,
TH32CS_SNAPPROCESS, TH32CS_SNAPPROCESS,
}; };
use winapi::um::winnt::HANDLE; use winapi::um::winnt::HANDLE;
@@ -703,7 +703,7 @@ impl CoreManager {
use winapi::um::processthreadsapi::OpenProcess; use winapi::um::processthreadsapi::OpenProcess;
use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION}; use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION};
let result = AsyncHandler::spawn_blocking(move || -> Result<bool> { AsyncHandler::spawn_blocking(move || -> Result<bool> {
unsafe { unsafe {
let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid); let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
if process_handle.is_null() { if process_handle.is_null() {
@@ -719,9 +719,7 @@ impl CoreManager {
Ok(exit_code == 259) Ok(exit_code == 259)
} }
}) })
.await?; .await?
result
} }
#[cfg(not(windows))] #[cfg(not(windows))]
@@ -767,16 +765,16 @@ impl CoreManager {
AsyncHandler::spawn(move || async move { AsyncHandler::spawn(move || async move {
while let Some(event) = rx.recv().await { while let Some(event) = rx.recv().await {
if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event { if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event
if let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line)) { && let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line))
logging!( {
error, logging!(
Type::Core, error,
true, Type::Core,
"[Sidecar] Failed to write stdout to file: {}", true,
e "[Sidecar] Failed to write stdout to file: {}",
); e
} );
} }
} }
}); });

View File

@@ -1,8 +1,8 @@
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
use tokio::time::{sleep, timeout, Duration}; use tokio::time::{Duration, sleep, timeout};
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
use crate::config::{Config, IVerge}; use crate::config::{Config, IVerge};
use crate::core::async_proxy_query::AsyncProxyQuery; use crate::core::async_proxy_query::AsyncProxyQuery;

View File

@@ -2,8 +2,9 @@ use crate::singleton;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::{ use std::{
sync::{ sync::{
Arc,
atomic::{AtomicU64, Ordering}, atomic::{AtomicU64, Ordering},
mpsc, Arc, mpsc,
}, },
thread, thread,
time::{Duration, Instant}, time::{Duration, Instant},
@@ -97,16 +98,14 @@ impl NotificationSystem {
let is_emergency = *system.emergency_mode.read(); let is_emergency = *system.emergency_mode.read();
if is_emergency { if is_emergency
if let FrontendEvent::NoticeMessage { ref status, .. } = event { && let FrontendEvent::NoticeMessage { ref status, .. } = event
if status == "info" { && status == "info" {
log::warn!( log::warn!(
"Emergency mode active, skipping info message" "Emergency mode active, skipping info message"
); );
continue; continue;
} }
}
}
if let Some(window) = handle.get_window() { if let Some(window) = handle.get_window() {
*system.last_emit_time.write() = Instant::now(); *system.last_emit_time.write() = Instant::now();
@@ -199,13 +198,12 @@ impl NotificationSystem {
/// 发送事件到队列 /// 发送事件到队列
fn send_event(&self, event: FrontendEvent) -> bool { fn send_event(&self, event: FrontendEvent) -> bool {
if *self.emergency_mode.read() { if *self.emergency_mode.read()
if let FrontendEvent::NoticeMessage { ref status, .. } = event { && let FrontendEvent::NoticeMessage { ref status, .. } = event
if status == "info" { && status == "info"
log::info!("Skipping info message in emergency mode"); {
return false; log::info!("Skipping info message in emergency mode");
} return false;
}
} }
if let Some(sender) = &self.sender { if let Some(sender) = &self.sender {
@@ -372,7 +370,9 @@ impl Handle {
if let Some(system) = system_opt.as_ref() { if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::ProfileUpdateStarted { uid }); system.send_event(FrontendEvent::ProfileUpdateStarted { uid });
} else { } else {
log::warn!("Notification system not initialized when trying to send ProfileUpdateStarted event."); log::warn!(
"Notification system not initialized when trying to send ProfileUpdateStarted event."
);
} }
} }
@@ -386,7 +386,9 @@ impl Handle {
if let Some(system) = system_opt.as_ref() { if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::ProfileUpdateCompleted { uid }); system.send_event(FrontendEvent::ProfileUpdateCompleted { uid });
} else { } else {
log::warn!("Notification system not initialized when trying to send ProfileUpdateCompleted event."); log::warn!(
"Notification system not initialized when trying to send ProfileUpdateCompleted event."
);
} }
} }

View File

@@ -1,10 +1,10 @@
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::utils::notification::{notify_event, NotificationEvent}; use crate::utils::notification::{NotificationEvent, notify_event};
use crate::{ use crate::{
config::Config, core::handle, feat, logging, logging_error, config::Config, core::handle, feat, logging, logging_error,
module::lightweight::entry_lightweight_mode, singleton_with_logging, utils::logging::Type, module::lightweight::entry_lightweight_mode, singleton_with_logging, utils::logging::Type,
}; };
use anyhow::{bail, Result}; use anyhow::{Result, bail};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{collections::HashMap, fmt, str::FromStr, sync::Arc}; use std::{collections::HashMap, fmt, str::FromStr, sync::Arc};
use tauri::{AppHandle, Manager}; use tauri::{AppHandle, Manager};
@@ -243,11 +243,11 @@ impl Hotkey {
); );
if hotkey_event_owned.key == Code::KeyQ && is_quit_owned { if hotkey_event_owned.key == Code::KeyQ && is_quit_owned {
if let Some(window) = app_handle_cloned.get_webview_window("main") { if let Some(window) = app_handle_cloned.get_webview_window("main")
if window.is_focused().unwrap_or(false) { && window.is_focused().unwrap_or(false)
logging!(debug, Type::Hotkey, "Executing quit function"); {
Self::execute_function(function_owned, &app_handle_cloned); logging!(debug, Type::Hotkey, "Executing quit function");
} Self::execute_function(function_owned, &app_handle_cloned);
} }
} else { } else {
logging!(debug, Type::Hotkey, "Executing function directly"); logging!(debug, Type::Hotkey, "Executing function directly");

View File

@@ -1,10 +1,10 @@
use crate::{ use crate::{
config::Config, config::Config,
core::service_ipc::{send_ipc_request, IpcCommand}, core::service_ipc::{IpcCommand, send_ipc_request},
logging, logging,
utils::{dirs, logging::Type}, utils::{dirs, logging::Type},
}; };
use anyhow::{bail, Context, Result}; use anyhow::{Context, Result, bail};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
env::current_exe, env::current_exe,
@@ -617,17 +617,11 @@ pub async fn check_service_version() -> Result<String> {
match response.data { match response.data {
Some(data) => { Some(data) => {
if let Some(nested_data) = data.get("data") { if let Some(nested_data) = data.get("data") {
if let Some(version) = nested_data.get("version") { if let Some(version) = nested_data.get("version")
if let Some(version_str) = version.as_str() { && let Some(version_str) = version.as_str()
logging!( {
info, logging!(info, Type::Service, true, "获取到服务版本: {}", version_str);
Type::Service, return Ok(version_str.to_string());
true,
"获取到服务版本: {}",
version_str
);
return Ok(version_str.to_string());
}
} }
logging!( logging!(
error, error,
@@ -792,25 +786,25 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
} }
// 添加对嵌套JSON结构的处理 // 添加对嵌套JSON结构的处理
if let Some(data) = &response.data { if let Some(data) = &response.data
if let Some(code) = data.get("code") { && let Some(code) = data.get("code")
let code_value = code.as_u64().unwrap_or(1); {
let msg = data let code_value = code.as_u64().unwrap_or(1);
.get("msg") let msg = data
.and_then(|m| m.as_str()) .get("msg")
.unwrap_or("未知错误"); .and_then(|m| m.as_str())
.unwrap_or("未知错误");
if code_value != 0 { if code_value != 0 {
logging!( logging!(
error, error,
Type::Service, Type::Service,
true, true,
"启动核心返回错误: code={}, msg={}", "启动核心返回错误: code={}, msg={}",
code_value, code_value,
msg msg
); );
bail!("启动核心失败: {}", msg); bail!("启动核心失败: {}", msg);
}
} }
} }
@@ -918,25 +912,25 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string())); bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string()));
} }
if let Some(data) = &response.data { if let Some(data) = &response.data
if let Some(code) = data.get("code") { && let Some(code) = data.get("code")
let code_value = code.as_u64().unwrap_or(1); {
let msg = data let code_value = code.as_u64().unwrap_or(1);
.get("msg") let msg = data
.and_then(|m| m.as_str()) .get("msg")
.unwrap_or("未知错误"); .and_then(|m| m.as_str())
.unwrap_or("未知错误");
if code_value != 0 { if code_value != 0 {
logging!( logging!(
error, error,
Type::Service, Type::Service,
true, true,
"停止核心返回错误: code={}, msg={}", "停止核心返回错误: code={}, msg={}",
code_value, code_value,
msg msg
); );
bail!("停止核心失败: {}", msg); bail!("停止核心失败: {}", msg);
}
} }
} }

View File

@@ -1,7 +1,7 @@
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::{logging, utils::logging::Type}; use crate::{logging, utils::logging::Type};
use anyhow::{bail, Context, Result}; use anyhow::{Context, Result, bail};
use hmac::{Hmac, Mac}; use hmac::{Hmac, Mac};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};

View File

@@ -2,7 +2,7 @@
use crate::utils::autostart as startup_shortcut; use crate::utils::autostart as startup_shortcut;
use crate::{ use crate::{
config::{Config, IVerge}, config::{Config, IVerge},
core::{handle::Handle, EventDrivenProxyManager}, core::{EventDrivenProxyManager, handle::Handle},
logging, logging_error, singleton_lazy, logging, logging_error, singleton_lazy,
utils::logging::Type, utils::logging::Type,
}; };
@@ -24,8 +24,7 @@ static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;172.17.*;
static DEFAULT_BYPASS: &str = static DEFAULT_BYPASS: &str =
"localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,::1"; "localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,::1";
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
static DEFAULT_BYPASS: &str = static DEFAULT_BYPASS: &str = "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,localhost,*.local,*.crashlytics.com,<local>";
"127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,localhost,*.local,*.crashlytics.com,<local>";
async fn get_bypass() -> String { async fn get_bypass() -> String {
let use_default = Config::verge() let use_default = Config::verge()

View File

@@ -6,8 +6,8 @@ use std::{
collections::HashMap, collections::HashMap,
pin::Pin, pin::Pin,
sync::{ sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
Arc, Arc,
atomic::{AtomicBool, AtomicU64, Ordering},
}, },
}; };
@@ -242,19 +242,18 @@ impl Timer {
if let Some(items) = Config::profiles().await.latest_ref().get_items() { if let Some(items) = Config::profiles().await.latest_ref().get_items() {
for item in items.iter() { for item in items.iter() {
if let Some(option) = item.option.as_ref() { if let Some(option) = item.option.as_ref()
if let (Some(interval), Some(uid)) = (option.update_interval, &item.uid) { && let (Some(interval), Some(uid)) = (option.update_interval, &item.uid)
if interval > 0 { && interval > 0
logging!( {
debug, logging!(
Type::Timer, debug,
"找到定时更新配置: uid={}, interval={}min", Type::Timer,
uid, "找到定时更新配置: uid={}, interval={}min",
interval uid,
); interval
new_map.insert(uid.clone(), interval); );
} new_map.insert(uid.clone(), interval);
}
} }
} }
} }
@@ -390,7 +389,8 @@ impl Timer {
}; };
// Get the profile updated timestamp - now safe to await // Get the profile updated timestamp - now safe to await
let profiles = { Config::profiles().await.clone().data_ref() }.clone(); let config_profiles = Config::profiles().await;
let profiles = config_profiles.data_ref().clone();
let items = match profiles.get_items() { let items = match profiles.get_items() {
Some(i) => i, Some(i) => i,
None => { None => {

View File

@@ -1,6 +1,6 @@
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use tauri::tray::TrayIconBuilder;
use tauri::Emitter; use tauri::Emitter;
use tauri::tray::TrayIconBuilder;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub mod speed_rate; pub mod speed_rate;
use crate::ipc::Rate; use crate::ipc::Rate;
@@ -8,7 +8,7 @@ use crate::module::lightweight;
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::utils::window_manager::WindowManager; use crate::utils::window_manager::WindowManager;
use crate::{ use crate::{
cmd, Type, cmd,
config::Config, config::Config,
feat, feat,
ipc::IpcManager, ipc::IpcManager,
@@ -16,7 +16,6 @@ use crate::{
module::lightweight::is_in_lightweight_mode, module::lightweight::is_in_lightweight_mode,
singleton_lazy, singleton_lazy,
utils::{dirs::find_target_icons, i18n::t}, utils::{dirs::find_target_icons, i18n::t},
Type,
}; };
use super::handle; use super::handle;
@@ -29,9 +28,9 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tauri::{ use tauri::{
AppHandle, Wry,
menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu}, menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu},
tray::{MouseButton, MouseButtonState, TrayIconEvent}, tray::{MouseButton, MouseButtonState, TrayIconEvent},
AppHandle, Wry,
}; };
#[derive(Clone)] #[derive(Clone)]
@@ -76,12 +75,11 @@ impl TrayState {
pub async fn get_common_tray_icon() -> (bool, Vec<u8>) { pub async fn get_common_tray_icon() -> (bool, Vec<u8>) {
let verge = Config::verge().await.latest_ref().clone(); let verge = Config::verge().await.latest_ref().clone();
let is_common_tray_icon = verge.common_tray_icon.unwrap_or(false); let is_common_tray_icon = verge.common_tray_icon.unwrap_or(false);
if is_common_tray_icon { if is_common_tray_icon
if let Ok(Some(common_icon_path)) = find_target_icons("common") { && let Ok(Some(common_icon_path)) = find_target_icons("common")
if let Ok(icon_data) = fs::read(common_icon_path) { && let Ok(icon_data) = fs::read(common_icon_path)
return (true, icon_data); {
} return (true, icon_data);
}
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
@@ -111,12 +109,11 @@ impl TrayState {
pub async fn get_sysproxy_tray_icon() -> (bool, Vec<u8>) { pub async fn get_sysproxy_tray_icon() -> (bool, Vec<u8>) {
let verge = Config::verge().await.latest_ref().clone(); let verge = Config::verge().await.latest_ref().clone();
let is_sysproxy_tray_icon = verge.sysproxy_tray_icon.unwrap_or(false); let is_sysproxy_tray_icon = verge.sysproxy_tray_icon.unwrap_or(false);
if is_sysproxy_tray_icon { if is_sysproxy_tray_icon
if let Ok(Some(sysproxy_icon_path)) = find_target_icons("sysproxy") { && let Ok(Some(sysproxy_icon_path)) = find_target_icons("sysproxy")
if let Ok(icon_data) = fs::read(sysproxy_icon_path) { && let Ok(icon_data) = fs::read(sysproxy_icon_path)
return (true, icon_data); {
} return (true, icon_data);
}
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
@@ -146,12 +143,11 @@ impl TrayState {
pub async fn get_tun_tray_icon() -> (bool, Vec<u8>) { pub async fn get_tun_tray_icon() -> (bool, Vec<u8>) {
let verge = Config::verge().await.latest_ref().clone(); let verge = Config::verge().await.latest_ref().clone();
let is_tun_tray_icon = verge.tun_tray_icon.unwrap_or(false); let is_tun_tray_icon = verge.tun_tray_icon.unwrap_or(false);
if is_tun_tray_icon { if is_tun_tray_icon
if let Ok(Some(tun_icon_path)) = find_target_icons("tun") { && let Ok(Some(tun_icon_path)) = find_target_icons("tun")
if let Ok(icon_data) = fs::read(tun_icon_path) { && let Ok(icon_data) = fs::read(tun_icon_path)
return (true, icon_data); {
} return (true, icon_data);
}
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
@@ -431,13 +427,13 @@ impl Tray {
{ {
let profiles = Config::profiles().await; let profiles = Config::profiles().await;
let profiles = profiles.latest_ref(); let profiles = profiles.latest_ref();
if let Some(current_profile_uid) = profiles.get_current() { if let Some(current_profile_uid) = profiles.get_current()
if let Ok(profile) = profiles.get_item(&current_profile_uid) { && let Ok(profile) = profiles.get_item(&current_profile_uid)
current_profile_name = match &profile.name { {
Some(profile_name) => profile_name.to_string(), current_profile_name = match &profile.name {
None => current_profile_name, Some(profile_name) => profile_name.to_string(),
}; None => current_profile_name,
} };
} }
} }

View File

@@ -1,7 +1,7 @@
#![cfg(target_os = "windows")] #![cfg(target_os = "windows")]
use crate::utils::dirs; use crate::utils::dirs;
use anyhow::{bail, Result}; use anyhow::{Result, bail};
use deelevate::{PrivilegeLevel, Token}; use deelevate::{PrivilegeLevel, Token};
use runas::Command as RunasCommand; use runas::Command as RunasCommand;
use std::process::Command as StdCommand; use std::process::Command as StdCommand;

View File

@@ -18,12 +18,10 @@ pub fn use_merge(merge: Mapping, config: Mapping) -> Mapping {
deep_merge(&mut config, &Value::from(merge)); deep_merge(&mut config, &Value::from(merge));
let config = config.as_mapping().cloned().unwrap_or_else(|| { config.as_mapping().cloned().unwrap_or_else(|| {
log::error!("Failed to convert merged config to mapping, using empty mapping"); log::error!("Failed to convert merged config to mapping, using empty mapping");
Mapping::new() Mapping::new()
}); })
config
} }
#[test] #[test]

View File

@@ -384,29 +384,26 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
if let Ok(app_dir) = dirs::app_home_dir() { if let Ok(app_dir) = dirs::app_home_dir() {
let dns_path = app_dir.join("dns_config.yaml"); let dns_path = app_dir.join("dns_config.yaml");
if dns_path.exists() { if dns_path.exists()
if let Ok(dns_yaml) = fs::read_to_string(&dns_path) { && let Ok(dns_yaml) = fs::read_to_string(&dns_path)
if let Ok(dns_config) = && let Ok(dns_config) = serde_yaml_ng::from_str::<serde_yaml_ng::Mapping>(&dns_yaml)
serde_yaml_ng::from_str::<serde_yaml_ng::Mapping>(&dns_yaml) {
{ // 处理hosts配置
// 处理hosts配置 if let Some(hosts_value) = dns_config.get("hosts")
if let Some(hosts_value) = dns_config.get("hosts") { && hosts_value.is_mapping()
if hosts_value.is_mapping() { {
config.insert("hosts".into(), hosts_value.clone()); config.insert("hosts".into(), hosts_value.clone());
log::info!(target: "app", "apply hosts configuration"); log::info!(target: "app", "apply hosts configuration");
} }
}
if let Some(dns_value) = dns_config.get("dns") { if let Some(dns_value) = dns_config.get("dns") {
if let Some(dns_mapping) = dns_value.as_mapping() { if let Some(dns_mapping) = dns_value.as_mapping() {
config.insert("dns".into(), dns_mapping.clone().into()); config.insert("dns".into(), dns_mapping.clone().into());
log::info!(target: "app", "apply dns_config.yaml (dns section)"); log::info!(target: "app", "apply dns_config.yaml (dns section)");
}
} else {
config.insert("dns".into(), dns_config.into());
log::info!(target: "app", "apply dns_config.yaml");
}
} }
} else {
config.insert("dns".into(), dns_config.into());
log::info!(target: "app", "apply dns_config.yaml");
} }
} }
} }

View File

@@ -7,7 +7,7 @@ pub fn use_script(
config: Mapping, config: Mapping,
name: String, name: String,
) -> Result<(Mapping, Vec<(String, String)>)> { ) -> Result<(Mapping, Vec<(String, String)>)> {
use boa_engine::{native_function::NativeFunction, Context, JsString, JsValue, Source}; use boa_engine::{Context, JsString, JsValue, Source, native_function::NativeFunction};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
let mut context = Context::default(); let mut context = Context::default();

View File

@@ -44,39 +44,39 @@ pub fn use_seq(seq: SeqMap, mut config: Mapping, field: &str) -> Mapping {
config.insert(Value::String(field.into()), Value::Sequence(new_seq)); config.insert(Value::String(field.into()), Value::Sequence(new_seq));
// If this is proxies field, we also need to filter proxy-groups // If this is proxies field, we also need to filter proxy-groups
if field == "proxies" { if field == "proxies"
if let Some(Value::Sequence(groups)) = config.get_mut("proxy-groups") { && let Some(Value::Sequence(groups)) = config.get_mut("proxy-groups")
let mut new_groups = Sequence::new(); {
for group in groups { let mut new_groups = Sequence::new();
if let Value::Mapping(group_map) = group { for group in groups {
let mut new_group = group_map.clone(); if let Value::Mapping(group_map) = group {
if let Some(Value::Sequence(proxies)) = group_map.get("proxies") { let mut new_group = group_map.clone();
let filtered_proxies: Sequence = proxies if let Some(Value::Sequence(proxies)) = group_map.get("proxies") {
.iter() let filtered_proxies: Sequence = proxies
.filter(|p| { .iter()
if let Value::String(name) = p { .filter(|p| {
!delete.contains(name) if let Value::String(name) = p {
} else { !delete.contains(name)
true } else {
} true
}) }
.cloned() })
.collect(); .cloned()
new_group.insert( .collect();
Value::String("proxies".into()), new_group.insert(
Value::Sequence(filtered_proxies), Value::String("proxies".into()),
); Value::Sequence(filtered_proxies),
} );
new_groups.push(Value::Mapping(new_group));
} else {
new_groups.push(group.clone());
} }
new_groups.push(Value::Mapping(new_group));
} else {
new_groups.push(group.clone());
} }
config.insert(
Value::String("proxy-groups".into()),
Value::Sequence(new_groups),
);
} }
config.insert(
Value::String("proxy-groups".into()),
Value::Sequence(new_groups),
);
} }
config config

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
config::Config, config::Config,
core::{handle, tray, CoreManager}, core::{CoreManager, handle, tray},
ipc::IpcManager, ipc::IpcManager,
logging_error, logging_error,
process::AsyncHandler, process::AsyncHandler,

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
config::{Config, IVerge}, config::{Config, IVerge},
core::{handle, hotkey, sysopt, tray, CoreManager}, core::{CoreManager, handle, hotkey, sysopt, tray},
logging_error, logging_error,
module::lightweight, module::lightweight,
utils::logging::Type, utils::logging::Type,
@@ -202,10 +202,10 @@ pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
if (update_flags & (UpdateFlags::SysProxy as i32)) != 0 { if (update_flags & (UpdateFlags::SysProxy as i32)) != 0 {
sysopt::Sysopt::global().update_sysproxy().await?; sysopt::Sysopt::global().update_sysproxy().await?;
} }
if (update_flags & (UpdateFlags::Hotkey as i32)) != 0 { if (update_flags & (UpdateFlags::Hotkey as i32)) != 0
if let Some(hotkeys) = patch.hotkeys { && let Some(hotkeys) = patch.hotkeys
hotkey::Hotkey::global().update(hotkeys).await?; {
} hotkey::Hotkey::global().update(hotkeys).await?;
} }
if (update_flags & (UpdateFlags::SystrayMenu as i32)) != 0 { if (update_flags & (UpdateFlags::SystrayMenu as i32)) != 0 {
tray::Tray::global().update_menu().await?; tray::Tray::global().update_menu().await?;

View File

@@ -1,11 +1,11 @@
use crate::{ use crate::{
cmd, cmd,
config::{profiles::profiles_draft_update_item_safe, Config, PrfItem, PrfOption}, config::{Config, PrfItem, PrfOption, profiles::profiles_draft_update_item_safe},
core::{handle, tray, CoreManager}, core::{CoreManager, handle, tray},
logging, logging,
utils::logging::Type, utils::logging::Type,
}; };
use anyhow::{bail, Result}; use anyhow::{Result, bail};
/// Toggle proxy profile /// Toggle proxy profile
pub async fn toggle_proxy_profile(profile_index: String) { pub async fn toggle_proxy_profile(profile_index: String) {

View File

@@ -13,21 +13,22 @@ pub async fn toggle_system_proxy() {
// 获取当前系统代理状态 // 获取当前系统代理状态
let enable = { let enable = {
let verge = Config::verge().await; let verge = Config::verge().await;
let enable = verge.latest_ref().enable_system_proxy.unwrap_or(false);
enable verge.latest_ref().enable_system_proxy.unwrap_or(false)
}; };
// 获取自动关闭连接设置 // 获取自动关闭连接设置
let auto_close_connection = { let auto_close_connection = {
let verge = Config::verge().await; let verge = Config::verge().await;
let auto_close = verge.latest_ref().auto_close_connection.unwrap_or(false);
auto_close verge.latest_ref().auto_close_connection.unwrap_or(false)
}; };
// 如果当前系统代理即将关闭且自动关闭连接设置为true则关闭所有连接 // 如果当前系统代理即将关闭且自动关闭连接设置为true则关闭所有连接
if enable && auto_close_connection { if enable
if let Err(err) = IpcManager::global().close_all_connections().await { && auto_close_connection
log::error!(target: "app", "Failed to close all connections: {err}"); && let Err(err) = IpcManager::global().close_all_connections().await
} {
log::error!(target: "app", "Failed to close all connections: {err}");
} }
let patch_result = super::patch_verge( let patch_result = super::patch_verge(

View File

@@ -1,7 +1,7 @@
use crate::utils::window_manager::WindowManager; use crate::utils::window_manager::WindowManager;
use crate::{ use crate::{
config::Config, config::Config,
core::{handle, sysopt, CoreManager}, core::{CoreManager, handle, sysopt},
ipc::IpcManager, ipc::IpcManager,
logging, logging,
module::lightweight, module::lightweight,
@@ -56,7 +56,7 @@ pub async fn quit() {
} }
async fn clean_async() -> bool { async fn clean_async() -> bool {
use tokio::time::{timeout, Duration}; use tokio::time::{Duration, timeout};
logging!(info, Type::System, true, "开始执行异步清理操作..."); logging!(info, Type::System, true, "开始执行异步清理操作...");
@@ -216,10 +216,10 @@ pub async fn hide() {
add_light_weight_timer().await; add_light_weight_timer().await;
} }
if let Some(window) = handle::Handle::global().get_window() { if let Some(window) = handle::Handle::global().get_window()
if window.is_visible().unwrap_or(false) { && window.is_visible().unwrap_or(false)
let _ = window.hide(); {
} let _ = window.hide();
} }
handle::Handle::global().set_activation_policy_accessory(); handle::Handle::global().set_activation_policy_accessory();
} }

View File

@@ -1,10 +1,10 @@
use std::time::Duration; use std::time::Duration;
use kode_bridge::{ use kode_bridge::{
errors::{AnyError, AnyResult},
ClientConfig, IpcHttpClient, LegacyResponse, ClientConfig, IpcHttpClient, LegacyResponse,
errors::{AnyError, AnyResult},
}; };
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
use crate::{ use crate::{
logging, singleton_with_logging, logging, singleton_with_logging,
@@ -199,8 +199,7 @@ impl IpcManager {
// 测速URL不再编码直接传递 // 测速URL不再编码直接传递
let url = format!("/proxies/{encoded_name}/delay?url={test_url}&timeout={timeout}"); let url = format!("/proxies/{encoded_name}/delay?url={test_url}&timeout={timeout}");
let response = self.send_request("GET", &url, None).await; self.send_request("GET", &url, None).await
response
} }
// 版本和配置相关 // 版本和配置相关
@@ -340,8 +339,7 @@ impl IpcManager {
// 测速URL不再编码直接传递 // 测速URL不再编码直接传递
let url = format!("/group/{encoded_group_name}/delay?url={test_url}&timeout={timeout}"); let url = format!("/group/{encoded_group_name}/delay?url={test_url}&timeout={timeout}");
let response = self.send_request("GET", &url, None).await; self.send_request("GET", &url, None).await
response
} }
// 调试相关 // 调试相关

View File

@@ -26,7 +26,7 @@ use tauri::Manager;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use tauri_plugin_autostart::MacosLauncher; use tauri_plugin_autostart::MacosLauncher;
use tauri_plugin_deep_link::DeepLinkExt; use tauri_plugin_deep_link::DeepLinkExt;
use tokio::time::{timeout, Duration}; use tokio::time::{Duration, timeout};
use utils::logging::Type; use utils::logging::Type;
/// Application initialization helper functions /// Application initialization helper functions
@@ -134,8 +134,8 @@ mod app_init {
} }
/// Generate all command handlers for the application /// Generate all command handlers for the application
pub fn generate_handlers( pub fn generate_handlers()
) -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static { -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static {
tauri::generate_handler![ tauri::generate_handler![
// Common commands // Common commands
cmd::get_sys_proxy, cmd::get_sys_proxy,
@@ -275,7 +275,9 @@ pub fn run() {
// Set Linux environment variable // Set Linux environment variable
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1"); unsafe {
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
}
let desktop_env = std::env::var("XDG_CURRENT_DESKTOP") let desktop_env = std::env::var("XDG_CURRENT_DESKTOP")
.unwrap_or_default() .unwrap_or_default()
@@ -284,7 +286,9 @@ pub fn run() {
let is_plasma_desktop = desktop_env.contains("PLASMA"); let is_plasma_desktop = desktop_env.contains("PLASMA");
if is_kde_desktop || is_plasma_desktop { if is_kde_desktop || is_plasma_desktop {
std::env::set_var("GTK_CSD", "0"); unsafe {
std::env::set_var("GTK_CSD", "0");
}
logging!( logging!(
info, info,
Type::Setup, Type::Setup,
@@ -438,10 +442,10 @@ pub fn run() {
} }
} }
if !is_enable_global_hotkey { if !is_enable_global_hotkey
if let Err(e) = hotkey::Hotkey::global().init().await { && let Err(e) = hotkey::Hotkey::global().init().await
logging!(error, Type::Hotkey, true, "Failed to init hotkeys: {}", e); {
} logging!(error, Type::Hotkey, true, "Failed to init hotkeys: {}", e);
} }
return; return;
} }
@@ -474,10 +478,8 @@ pub fn run() {
} }
} }
if !is_enable_global_hotkey { if !is_enable_global_hotkey && let Err(e) = hotkey::Hotkey::global().reset() {
if let Err(e) = hotkey::Hotkey::global().reset() { logging!(error, Type::Hotkey, true, "Failed to reset hotkeys: {}", e);
logging!(error, Type::Hotkey, true, "Failed to reset hotkeys: {}", e);
}
} }
}); });
} }

View File

@@ -13,7 +13,7 @@ use crate::logging_error;
use crate::utils::window_manager::WindowManager; use crate::utils::window_manager::WindowManager;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use delay_timer::prelude::TaskBuilder; use delay_timer::prelude::TaskBuilder;
use std::sync::atomic::{AtomicU32, AtomicU8, Ordering}; use std::sync::atomic::{AtomicU8, AtomicU32, Ordering};
use tauri::Listener; use tauri::Listener;
const LIGHT_WEIGHT_TASK_UID: &str = "light_weight_task"; const LIGHT_WEIGHT_TASK_UID: &str = "light_weight_task";

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
cmd::system, cmd::system,
core::{handle, CoreManager}, core::{CoreManager, handle},
}; };
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use sysinfo::System; use sysinfo::System;
@@ -20,7 +20,13 @@ impl Debug for PlatformSpecification {
write!( write!(
f, f,
"System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}\nVerge Version: {}\nRunning Mode: {}\nIs Admin: {}", "System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}\nVerge Version: {}\nRunning Mode: {}\nIs Admin: {}",
self.system_name, self.system_version, self.system_kernel_version, self.system_arch, self.verge_version, self.running_mode, self.is_admin self.system_name,
self.system_version,
self.system_kernel_version,
self.system_arch,
self.verge_version,
self.running_mode,
self.is_admin
) )
} }
} }

View File

@@ -67,12 +67,18 @@ impl AsyncHandler {
location.column() location.column()
); );
println!("┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐"); println!(
"┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐"
);
println!("{:<18}{:<80}", "Field", "Value"); println!("{:<18}{:<80}", "Field", "Value");
println!("├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤"); println!(
"├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤"
);
println!("{:<18}{:<80}", "Type of task", type_str); println!("{:<18}{:<80}", "Type of task", type_str);
println!("{:<18}{:<80}", "Size of task", size_str); println!("{:<18}{:<80}", "Size of task", size_str);
println!("{:<18}{:<80}", "Called from", loc_str); println!("{:<18}{:<80}", "Called from", loc_str);
println!("└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘"); println!(
"└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘"
);
} }
} }

View File

@@ -1,5 +1,5 @@
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use anyhow::{anyhow, Result}; use anyhow::{Result, anyhow};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use log::info; use log::info;

View File

@@ -151,12 +151,11 @@ pub fn find_target_icons(target: &str) -> Result<Option<String>> {
let entry = entry?; let entry = entry?;
let path = entry.path(); let path = entry.path();
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) { if let Some(file_name) = path.file_name().and_then(|n| n.to_str())
if file_name.starts_with(target) && file_name.starts_with(target)
&& (file_name.ends_with(".ico") || file_name.ends_with(".png")) && (file_name.ends_with(".ico") || file_name.ends_with(".png"))
{ {
matching_files.push(path); matching_files.push(path);
}
} }
} }

View File

@@ -1,7 +1,7 @@
use crate::{enhance::seq::SeqMap, logging, utils::logging::Type}; use crate::{enhance::seq::SeqMap, logging, utils::logging::Type};
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{Context, Result, anyhow, bail};
use nanoid::nanoid; use nanoid::nanoid;
use serde::{de::DeserializeOwned, Serialize}; use serde::{Serialize, de::DeserializeOwned};
use serde_yaml_ng::Mapping; use serde_yaml_ng::Mapping;
use std::{path::PathBuf, str::FromStr}; use std::{path::PathBuf, str::FromStr};
@@ -154,10 +154,6 @@ macro_rules! ret_err {
#[macro_export] #[macro_export]
macro_rules! t { macro_rules! t {
($en:expr, $zh:expr, $use_zh:expr) => { ($en:expr, $zh:expr, $use_zh:expr) => {
if $use_zh { if $use_zh { $zh } else { $en }
$zh
} else {
$en
}
}; };
} }

View File

@@ -15,14 +15,14 @@ fn get_locales_dir() -> Option<PathBuf> {
pub fn get_supported_languages() -> Vec<String> { pub fn get_supported_languages() -> Vec<String> {
let mut languages = Vec::new(); let mut languages = Vec::new();
if let Some(locales_dir) = get_locales_dir() { if let Some(locales_dir) = get_locales_dir()
if let Ok(entries) = fs::read_dir(locales_dir) { && let Ok(entries) = fs::read_dir(locales_dir)
for entry in entries.flatten() { {
if let Some(file_name) = entry.file_name().to_str() { for entry in entries.flatten() {
if let Some(lang) = file_name.strip_suffix(".json") { if let Some(file_name) = entry.file_name().to_str()
languages.push(lang.to_string()); && let Some(lang) = file_name.strip_suffix(".json")
} {
} languages.push(lang.to_string());
} }
} }
} }
@@ -39,10 +39,10 @@ static TRANSLATIONS: Lazy<HashMap<String, Value>> = Lazy::new(|| {
if let Some(locales_dir) = get_locales_dir() { if let Some(locales_dir) = get_locales_dir() {
for lang in get_supported_languages() { for lang in get_supported_languages() {
let file_path = locales_dir.join(format!("{lang}.json")); let file_path = locales_dir.join(format!("{lang}.json"));
if let Ok(content) = fs::read_to_string(file_path) { if let Ok(content) = fs::read_to_string(file_path)
if let Ok(json) = serde_json::from_str(&content) { && let Ok(json) = serde_json::from_str(&content)
translations.insert(lang.to_string(), json); {
} translations.insert(lang.to_string(), json);
} }
} }
} }
@@ -76,14 +76,13 @@ pub async fn t(key: &str) -> String {
return text.to_string(); return text.to_string();
} }
if current_lang != DEFAULT_LANGUAGE { if current_lang != DEFAULT_LANGUAGE
if let Some(text) = TRANSLATIONS && let Some(text) = TRANSLATIONS
.get(DEFAULT_LANGUAGE) .get(DEFAULT_LANGUAGE)
.and_then(|trans| trans.get(&key)) .and_then(|trans| trans.get(&key))
.and_then(|val| val.as_str()) .and_then(|val| val.as_str())
{ {
return text.to_string(); return text.to_string();
}
} }
key key

View File

@@ -296,52 +296,52 @@ async fn ensure_directories() -> Result<()> {
/// 初始化配置文件 /// 初始化配置文件
async fn initialize_config_files() -> Result<()> { async fn initialize_config_files() -> Result<()> {
if let Ok(path) = dirs::clash_path() { if let Ok(path) = dirs::clash_path()
if !path.exists() { && !path.exists()
let template = IClashTemp::template().0; {
help::save_yaml(&path, &template, Some("# Clash Verge")) let template = IClashTemp::template().0;
.await help::save_yaml(&path, &template, Some("# Clash Verge"))
.map_err(|e| anyhow::anyhow!("Failed to create clash config: {}", e))?; .await
logging!( .map_err(|e| anyhow::anyhow!("Failed to create clash config: {}", e))?;
info, logging!(
Type::Setup, info,
true, Type::Setup,
"Created clash config at {:?}", true,
path "Created clash config at {:?}",
); path
} );
} }
if let Ok(path) = dirs::verge_path() { if let Ok(path) = dirs::verge_path()
if !path.exists() { && !path.exists()
let template = IVerge::template(); {
help::save_yaml(&path, &template, Some("# Clash Verge")) let template = IVerge::template();
.await help::save_yaml(&path, &template, Some("# Clash Verge"))
.map_err(|e| anyhow::anyhow!("Failed to create verge config: {}", e))?; .await
logging!( .map_err(|e| anyhow::anyhow!("Failed to create verge config: {}", e))?;
info, logging!(
Type::Setup, info,
true, Type::Setup,
"Created verge config at {:?}", true,
path "Created verge config at {:?}",
); path
} );
} }
if let Ok(path) = dirs::profiles_path() { if let Ok(path) = dirs::profiles_path()
if !path.exists() { && !path.exists()
let template = IProfiles::template(); {
help::save_yaml(&path, &template, Some("# Clash Verge")) let template = IProfiles::template();
.await help::save_yaml(&path, &template, Some("# Clash Verge"))
.map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?; .await
logging!( .map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?;
info, logging!(
Type::Setup, info,
true, Type::Setup,
"Created profiles config at {:?}", true,
path "Created profiles config at {:?}",
); path
} );
} }
// 验证并修正verge配置 // 验证并修正verge配置
@@ -459,7 +459,7 @@ pub async fn init_resources() -> Result<()> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub fn init_scheme() -> Result<()> { pub fn init_scheme() -> Result<()> {
use tauri::utils::platform::current_exe; use tauri::utils::platform::current_exe;
use winreg::{enums::*, RegKey}; use winreg::{RegKey, enums::*};
let app_exe = current_exe()?; let app_exe = current_exe()?;
let app_exe = dunce::canonicalize(app_exe)?; let app_exe = dunce::canonicalize(app_exe)?;

View File

@@ -1,14 +1,14 @@
use anyhow::Result; use anyhow::Result;
use base64::{engine::general_purpose, Engine as _}; use base64::{Engine as _, engine::general_purpose};
use isahc::prelude::*; use isahc::prelude::*;
use isahc::{HttpClient, config::SslOption};
use isahc::{ use isahc::{
config::RedirectPolicy, config::RedirectPolicy,
http::{ http::{
header::{HeaderMap, HeaderValue, USER_AGENT},
StatusCode, Uri, StatusCode, Uri,
header::{HeaderMap, HeaderValue, USER_AGENT},
}, },
}; };
use isahc::{config::SslOption, HttpClient};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use sysproxy::Sysproxy; use sysproxy::Sysproxy;
use tauri::Url; use tauri::Url;
@@ -88,10 +88,11 @@ impl NetworkManager {
return true; return true;
} }
if let Some((time, _)) = &*last_error_guard { if let Some((time, _)) = &*last_error_guard
if time.elapsed() < Duration::from_secs(30) && count > 2 { && time.elapsed() < Duration::from_secs(30)
return true; && count > 2
} {
return true;
} }
false false
@@ -113,7 +114,8 @@ impl NetworkManager {
) -> Result<HttpClient> { ) -> Result<HttpClient> {
let proxy_uri_clone = proxy_uri.clone(); let proxy_uri_clone = proxy_uri.clone();
let headers_clone = default_headers.clone(); let headers_clone = default_headers.clone();
let client = {
{
let mut builder = HttpClient::builder(); let mut builder = HttpClient::builder();
builder = match proxy_uri_clone { builder = match proxy_uri_clone {
@@ -136,9 +138,7 @@ impl NetworkManager {
builder = builder.redirect_policy(RedirectPolicy::Follow); builder = builder.redirect_policy(RedirectPolicy::Follow);
Ok(builder.build()?) Ok(builder.build()?)
}; }
client
} }
pub async fn create_request( pub async fn create_request(
@@ -200,15 +200,15 @@ impl NetworkManager {
let parsed = Url::parse(url)?; let parsed = Url::parse(url)?;
let mut extra_headers = HeaderMap::new(); let mut extra_headers = HeaderMap::new();
if !parsed.username().is_empty() { if !parsed.username().is_empty()
if let Some(pass) = parsed.password() { && let Some(pass) = parsed.password()
let auth_str = format!("{}:{}", parsed.username(), pass); {
let encoded = general_purpose::STANDARD.encode(auth_str); let auth_str = format!("{}:{}", parsed.username(), pass);
extra_headers.insert( let encoded = general_purpose::STANDARD.encode(auth_str);
"Authorization", extra_headers.insert(
HeaderValue::from_str(&format!("Basic {}", encoded))?, "Authorization",
); HeaderValue::from_str(&format!("Basic {}", encoded))?,
} );
} }
let clean_url = { let clean_url = {

View File

@@ -3,7 +3,7 @@ use tauri::AppHandle;
use crate::{ use crate::{
config::Config, config::Config,
core::{handle, hotkey::Hotkey, sysopt, tray::Tray, CoreManager, Timer}, core::{CoreManager, Timer, handle, hotkey::Hotkey, sysopt, tray::Tray},
logging, logging_error, logging, logging_error,
module::lightweight::auto_lightweight_mode_init, module::lightweight::auto_lightweight_mode_init,
process::AsyncHandler, process::AsyncHandler,

View File

@@ -1,4 +1,4 @@
use anyhow::{bail, Result}; use anyhow::{Result, bail};
use percent_encoding::percent_decode_str; use percent_encoding::percent_decode_str;
use tauri::Url; use tauri::Url;

View File

@@ -1,8 +1,8 @@
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::sync::{ use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Arc,
atomic::{AtomicBool, Ordering},
}; };
use tokio::sync::Notify; use tokio::sync::Notify;

View File

@@ -10,7 +10,7 @@ use crate::{
utils::{ utils::{
logging::Type, logging::Type,
resolve::{ resolve::{
ui::{get_ui_ready, update_ui_ready_stage, wait_for_ui_ready, UiReadyStage}, ui::{UiReadyStage, get_ui_ready, update_ui_ready_stage, wait_for_ui_ready},
window_script::{INITIAL_LOADING_OVERLAY, WINDOW_INITIAL_SCRIPT}, window_script::{INITIAL_LOADING_OVERLAY, WINDOW_INITIAL_SCRIPT},
}, },
}, },
@@ -37,22 +37,22 @@ fn get_current_timestamp() -> u32 {
/// 检查是否已存在窗口,如果存在则显示并返回 true /// 检查是否已存在窗口,如果存在则显示并返回 true
fn check_existing_window(is_show: bool) -> Option<bool> { fn check_existing_window(is_show: bool) -> Option<bool> {
if let Some(app_handle) = handle::Handle::global().app_handle() { if let Some(app_handle) = handle::Handle::global().app_handle()
if let Some(window) = app_handle.get_webview_window("main") { && let Some(window) = app_handle.get_webview_window("main")
logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口"); {
if is_show { logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口");
if window.is_minimized().unwrap_or(false) { if is_show {
logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化"); if window.is_minimized().unwrap_or(false) {
let _ = window.unminimize(); logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化");
} let _ = window.unminimize();
let _ = window.show();
let _ = window.set_focus();
#[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_regular();
} }
return Some(true); let _ = window.show();
let _ = window.set_focus();
#[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_regular();
} }
return Some(true);
} }
None None
} }

View File

@@ -1,11 +1,11 @@
use super::resolve; use super::resolve;
use crate::{ use crate::{
config::{Config, IVerge, DEFAULT_PAC}, config::{Config, DEFAULT_PAC, IVerge},
logging_error, logging_error,
process::AsyncHandler, process::AsyncHandler,
utils::logging::Type, utils::logging::Type,
}; };
use anyhow::{bail, Result}; use anyhow::{Result, bail};
use port_scanner::local_port_available; use port_scanner::local_port_available;
use warp::Filter; use warp::Filter;