feat: update Cargo.toml for 2024 edition and optimize release profiles (#4681)

* 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
This commit is contained in:
Tunglies
2025-09-08 13:57:32 +08:00
committed by GitHub
parent 58a0089b19
commit 31e3104c7f
51 changed files with 780 additions and 791 deletions

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
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::wrap_err;
use network_interface::NetworkInterface;

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
use crate::utils::dirs::get_encryption_key;
use aes_gcm::{
aead::{Aead, KeyInit},
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};
const NONCE_LENGTH: usize = 12;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,8 +2,9 @@ use crate::singleton;
use parking_lot::RwLock;
use std::{
sync::{
Arc,
atomic::{AtomicU64, Ordering},
mpsc, Arc,
mpsc,
},
thread,
time::{Duration, Instant},
@@ -98,16 +99,14 @@ impl NotificationSystem {
let is_emergency = *system.emergency_mode.read();
if is_emergency {
if let FrontendEvent::NoticeMessage { ref status, .. } = event {
if status == "info" {
if is_emergency
&& let FrontendEvent::NoticeMessage { ref status, .. } = event
&& status == "info" {
log::warn!(
"Emergency mode active, skipping info message"
);
continue;
}
}
}
if let Some(window) = handle.get_window() {
*system.last_emit_time.write() = Instant::now();
@@ -203,13 +202,12 @@ impl NotificationSystem {
/// 发送事件到队列
fn send_event(&self, event: FrontendEvent) -> bool {
if *self.emergency_mode.read() {
if let FrontendEvent::NoticeMessage { ref status, .. } = event {
if status == "info" {
log::info!("Skipping info message in emergency mode");
return false;
}
}
if *self.emergency_mode.read()
&& let FrontendEvent::NoticeMessage { ref status, .. } = event
&& status == "info"
{
log::info!("Skipping info message in emergency mode");
return false;
}
if let Some(sender) = &self.sender {
@@ -392,7 +390,9 @@ impl Handle {
if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::ProfileUpdateStarted { uid });
} 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."
);
}
}
@@ -406,7 +406,9 @@ impl Handle {
if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::ProfileUpdateCompleted { uid });
} 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::utils::notification::{notify_event, NotificationEvent};
use crate::utils::notification::{NotificationEvent, notify_event};
use crate::{
config::Config, core::handle, feat, logging, logging_error,
module::lightweight::entry_lightweight_mode, singleton_with_logging, utils::logging::Type,
};
use anyhow::{bail, Result};
use anyhow::{Result, bail};
use parking_lot::Mutex;
use std::{collections::HashMap, fmt, str::FromStr, sync::Arc};
use tauri::{AppHandle, Manager};
@@ -243,11 +243,11 @@ impl Hotkey {
);
if hotkey_event_owned.key == Code::KeyQ && is_quit_owned {
if let Some(window) = app_handle_cloned.get_webview_window("main") {
if window.is_focused().unwrap_or(false) {
logging!(debug, Type::Hotkey, "Executing quit function");
Self::execute_function(function_owned, &app_handle_cloned);
}
if let Some(window) = app_handle_cloned.get_webview_window("main")
&& window.is_focused().unwrap_or(false)
{
logging!(debug, Type::Hotkey, "Executing quit function");
Self::execute_function(function_owned, &app_handle_cloned);
}
} else {
logging!(debug, Type::Hotkey, "Executing function directly");

View File

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

View File

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

View File

@@ -2,7 +2,7 @@
use crate::utils::autostart as startup_shortcut;
use crate::{
config::{Config, IVerge},
core::{handle::Handle, EventDrivenProxyManager},
core::{EventDrivenProxyManager, handle::Handle},
logging, logging_error, singleton_lazy,
utils::logging::Type,
};
@@ -24,8 +24,7 @@ static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;172.17.*;
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";
#[cfg(target_os = "macos")]
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>";
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>";
async fn get_bypass() -> String {
let use_default = Config::verge()

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
#![cfg(target_os = "windows")]
use crate::utils::dirs;
use anyhow::{bail, Result};
use anyhow::{Result, bail};
use deelevate::{PrivilegeLevel, Token};
use runas::Command as RunasCommand;
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));
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");
Mapping::new()
});
config
})
}
#[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() {
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_ng::from_str::<serde_yaml_ng::Mapping>(&dns_yaml)
{
// 处理hosts配置
if let Some(hosts_value) = dns_config.get("hosts") {
if hosts_value.is_mapping() {
config.insert("hosts".into(), hosts_value.clone());
log::info!(target: "app", "apply hosts configuration");
}
}
if dns_path.exists()
&& let Ok(dns_yaml) = fs::read_to_string(&dns_path)
&& let Ok(dns_config) = serde_yaml_ng::from_str::<serde_yaml_ng::Mapping>(&dns_yaml)
{
// 处理hosts配置
if let Some(hosts_value) = dns_config.get("hosts")
&& hosts_value.is_mapping()
{
config.insert("hosts".into(), hosts_value.clone());
log::info!(target: "app", "apply hosts configuration");
}
if let Some(dns_value) = dns_config.get("dns") {
if let Some(dns_mapping) = dns_value.as_mapping() {
config.insert("dns".into(), dns_mapping.clone().into());
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");
}
if let Some(dns_value) = dns_config.get("dns") {
if let Some(dns_mapping) = dns_value.as_mapping() {
config.insert("dns".into(), dns_mapping.clone().into());
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");
}
}
}

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
use crate::{
config::{Config, IVerge},
core::{handle, hotkey, sysopt, tray, CoreManager},
core::{CoreManager, handle, hotkey, sysopt, tray},
logging_error,
module::lightweight,
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 {
sysopt::Sysopt::global().update_sysproxy().await?;
}
if (update_flags & (UpdateFlags::Hotkey as i32)) != 0 {
if let Some(hotkeys) = patch.hotkeys {
hotkey::Hotkey::global().update(hotkeys).await?;
}
if (update_flags & (UpdateFlags::Hotkey as i32)) != 0
&& let Some(hotkeys) = patch.hotkeys
{
hotkey::Hotkey::global().update(hotkeys).await?;
}
if (update_flags & (UpdateFlags::SystrayMenu as i32)) != 0 {
tray::Tray::global().update_menu().await?;

View File

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

View File

@@ -13,21 +13,22 @@ pub async fn toggle_system_proxy() {
// 获取当前系统代理状态
let enable = {
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 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则关闭所有连接
if enable && auto_close_connection {
if let Err(err) = IpcManager::global().close_all_connections().await {
log::error!(target: "app", "Failed to close all connections: {err}");
}
if enable
&& auto_close_connection
&& 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(

View File

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

View File

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

View File

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

View File

@@ -7,6 +7,7 @@ use crate::{
utils::{logging::Type, window_manager::WindowManager},
};
#[cfg(target_os = "macos")]
use crate::logging_error;
use anyhow::{Context, Result};
@@ -136,13 +137,13 @@ pub async fn entry_lightweight_mode() {
result
);
if let Some(window) = handle::Handle::global().get_window() {
if let Some(webview) = window.get_webview_window("main") {
let _ = webview.destroy();
}
#[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_accessory();
if let Some(window) = handle::Handle::global().get_window()
&& let Some(webview) = window.get_webview_window("main")
{
let _ = webview.destroy();
}
#[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_accessory();
set_lightweight_mode(true).await;
let _ = cancel_light_weight_timer();
ProxyRequestCache::global().clean_default_keys();

View File

@@ -1,6 +1,6 @@
use crate::{
cmd::system,
core::{handle, CoreManager},
core::{CoreManager, handle},
};
use std::fmt::{self, Debug, Formatter};
use sysinfo::System;
@@ -20,7 +20,13 @@ impl Debug for PlatformSpecification {
write!(
f,
"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()
);
println!("┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐");
println!(
"┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐"
);
println!("{:<18}{:<80}", "Field", "Value");
println!("├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤");
println!(
"├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤"
);
println!("{:<18}{:<80}", "Type of task", type_str);
println!("{:<18}{:<80}", "Size of task", size_str);
println!("{:<18}{:<80}", "Called from", loc_str);
println!("└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘");
println!(
"└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘"
);
}
}

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
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 serde::{de::DeserializeOwned, Serialize};
use serde::{Serialize, de::DeserializeOwned};
use serde_yaml_ng::Mapping;
use std::{path::PathBuf, str::FromStr};
@@ -154,10 +154,6 @@ macro_rules! ret_err {
#[macro_export]
macro_rules! t {
($en:expr, $zh:expr, $use_zh:expr) => {
if $use_zh {
$zh
} else {
$en
}
if $use_zh { $zh } else { $en }
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ use crate::{
utils::{
logging::Type,
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},
},
},
@@ -34,22 +34,22 @@ fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> {
/// 检查是否已存在窗口,如果存在则显示并返回 true
fn check_existing_window(is_show: bool) -> Option<bool> {
if let Some(app_handle) = handle::Handle::global().app_handle() {
if let Some(window) = app_handle.get_webview_window("main") {
logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口");
if is_show {
if window.is_minimized().unwrap_or(false) {
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();
if let Some(app_handle) = handle::Handle::global().app_handle()
&& let Some(window) = app_handle.get_webview_window("main")
{
logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口");
if is_show {
if window.is_minimized().unwrap_or(false) {
logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化");
let _ = window.unminimize();
}
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
}

View File

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