refactor: fix formating in rust
This commit is contained in:
@@ -6,14 +6,14 @@ use crate::{
|
|||||||
utils::{dirs, help, logging::Type},
|
utils::{dirs, help, logging::Type},
|
||||||
wrap_err,
|
wrap_err,
|
||||||
};
|
};
|
||||||
|
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||||
|
use percent_encoding::percent_decode_str;
|
||||||
|
use serde_yaml::Value;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::{Mutex, RwLock};
|
use tokio::sync::{Mutex, RwLock};
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use serde_yaml::Value;
|
|
||||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
|
||||||
use percent_encoding::percent_decode_str;
|
|
||||||
|
|
||||||
// 全局互斥锁防止并发配置更新
|
// 全局互斥锁防止并发配置更新
|
||||||
static PROFILE_UPDATE_MUTEX: Mutex<()> = Mutex::const_new(());
|
static PROFILE_UPDATE_MUTEX: Mutex<()> = Mutex::const_new(());
|
||||||
@@ -138,20 +138,34 @@ pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult
|
|||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles = profiles.latest();
|
let profiles = profiles.latest();
|
||||||
|
|
||||||
profiles.items.as_ref()
|
profiles
|
||||||
|
.items
|
||||||
|
.as_ref()
|
||||||
.and_then(|items| items.iter().find(|item| item.url.as_deref() == Some(&url)))
|
.and_then(|items| items.iter().find(|item| item.url.as_deref() == Some(&url)))
|
||||||
.and_then(|item| item.uid.clone())
|
.and_then(|item| item.uid.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(uid) = existing_uid {
|
if let Some(uid) = existing_uid {
|
||||||
logging!(info, Type::Cmd, true, "The profile with URL {} already exists (UID: {}). Running the update...", url, uid);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"The profile with URL {} already exists (UID: {}). Running the update...",
|
||||||
|
url,
|
||||||
|
uid
|
||||||
|
);
|
||||||
update_profile(uid, option).await
|
update_profile(uid, option).await
|
||||||
} else {
|
} else {
|
||||||
logging!(info, Type::Cmd, true, "Profile with URL {} not found. Create a new one...", url);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"Profile with URL {} not found. Create a new one...",
|
||||||
|
url
|
||||||
|
);
|
||||||
let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
|
let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
|
||||||
wrap_err!(Config::profiles().data().append_item(item))
|
wrap_err!(Config::profiles().data().append_item(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 重新排序配置文件
|
/// 重新排序配置文件
|
||||||
@@ -181,20 +195,29 @@ pub async fn delete_profile(index: String) -> CmdResult {
|
|||||||
{
|
{
|
||||||
let profiles_config = Config::profiles();
|
let profiles_config = Config::profiles();
|
||||||
let mut profiles_data = profiles_config.data();
|
let mut profiles_data = profiles_config.data();
|
||||||
should_update = profiles_data.delete_item(index.clone()).map_err(|e| e.to_string())?;
|
should_update = profiles_data
|
||||||
|
.delete_item(index.clone())
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
let was_last_profile = profiles_data.items.as_ref().map_or(true, |items| {
|
let was_last_profile = profiles_data.items.as_ref().is_none_or(|items| {
|
||||||
!items.iter().any(|item|
|
!items
|
||||||
item.itype == Some("remote".to_string()) || item.itype == Some("local".to_string())
|
.iter()
|
||||||
)
|
.any(|item| matches!(item.itype.as_deref(), Some("remote") | Some("local")))
|
||||||
});
|
});
|
||||||
|
|
||||||
if was_last_profile {
|
if was_last_profile {
|
||||||
logging!(info, Type::Cmd, true, "The last profile has been deleted. Disabling proxy modes...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"The last profile has been deleted. Disabling proxy modes..."
|
||||||
|
);
|
||||||
let verge_config = Config::verge();
|
let verge_config = Config::verge();
|
||||||
let mut verge_data = verge_config.data();
|
let mut verge_data = verge_config.data();
|
||||||
|
|
||||||
if verge_data.enable_tun_mode == Some(true) || verge_data.enable_system_proxy == Some(true) {
|
if verge_data.enable_tun_mode == Some(true)
|
||||||
|
|| verge_data.enable_system_proxy == Some(true)
|
||||||
|
{
|
||||||
verge_data.enable_tun_mode = Some(false);
|
verge_data.enable_tun_mode = Some(false);
|
||||||
verge_data.enable_system_proxy = Some(false);
|
verge_data.enable_system_proxy = Some(false);
|
||||||
verge_data.save_file().map_err(|e| e.to_string())?;
|
verge_data.save_file().map_err(|e| e.to_string())?;
|
||||||
@@ -696,23 +719,30 @@ pub fn get_next_update_time(uid: String) -> CmdResult<Option<i64>> {
|
|||||||
Ok(next_time)
|
Ok(next_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn update_profiles_on_startup() -> CmdResult {
|
pub async fn update_profiles_on_startup() -> CmdResult {
|
||||||
logging!(info, Type::Cmd, true, "Checking profiles for updates at startup...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"Checking profiles for updates at startup..."
|
||||||
|
);
|
||||||
|
|
||||||
let profiles_to_update = {
|
let profiles_to_update = {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles = profiles.latest();
|
let profiles = profiles.latest();
|
||||||
|
|
||||||
profiles.items.as_ref()
|
profiles.items.as_ref().map_or_else(Vec::new, |items| {
|
||||||
.map_or_else(
|
items
|
||||||
Vec::new,
|
.iter()
|
||||||
|items| items.iter()
|
.filter(|item| {
|
||||||
.filter(|item| item.option.as_ref().is_some_and(|opt| opt.update_always == Some(true)))
|
item.option
|
||||||
.filter_map(|item| item.uid.clone())
|
.as_ref()
|
||||||
.collect()
|
.is_some_and(|opt| opt.update_always == Some(true))
|
||||||
)
|
})
|
||||||
|
.filter_map(|item| item.uid.clone())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
if profiles_to_update.is_empty() {
|
if profiles_to_update.is_empty() {
|
||||||
@@ -720,7 +750,13 @@ pub async fn update_profiles_on_startup() -> CmdResult {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
logging!(info, Type::Cmd, true, "Found profiles to update: {:?}", profiles_to_update);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"Found profiles to update: {:?}",
|
||||||
|
profiles_to_update
|
||||||
|
);
|
||||||
|
|
||||||
let mut update_futures = Vec::new();
|
let mut update_futures = Vec::new();
|
||||||
for uid in profiles_to_update {
|
for uid in profiles_to_update {
|
||||||
@@ -729,13 +765,25 @@ pub async fn update_profiles_on_startup() -> CmdResult {
|
|||||||
|
|
||||||
let results = futures::future::join_all(update_futures).await;
|
let results = futures::future::join_all(update_futures).await;
|
||||||
|
|
||||||
|
|
||||||
if results.iter().any(|res| res.is_ok()) {
|
if results.iter().any(|res| res.is_ok()) {
|
||||||
logging!(info, Type::Cmd, true, "The startup update is complete, restart the kernel...");
|
logging!(
|
||||||
CoreManager::global().update_config().await.map_err(|e| e.to_string())?;
|
info,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"The startup update is complete, restart the kernel..."
|
||||||
|
);
|
||||||
|
CoreManager::global()
|
||||||
|
.update_config()
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
handle::Handle::refresh_clash();
|
handle::Handle::refresh_clash();
|
||||||
} else {
|
} else {
|
||||||
logging!(warn, Type::Cmd, true, "All updates completed with errors on startup.");
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"All updates completed with errors on startup."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -743,7 +791,6 @@ pub async fn update_profiles_on_startup() -> CmdResult {
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn create_profile_from_share_link(link: String, template_name: String) -> CmdResult {
|
pub async fn create_profile_from_share_link(link: String, template_name: String) -> CmdResult {
|
||||||
|
|
||||||
const DEFAULT_TEMPLATE: &str = r#"
|
const DEFAULT_TEMPLATE: &str = r#"
|
||||||
mixed-port: 2080
|
mixed-port: 2080
|
||||||
allow-lan: true
|
allow-lan: true
|
||||||
@@ -1107,14 +1154,18 @@ pub async fn create_profile_from_share_link(link: String, template_name: String)
|
|||||||
|
|
||||||
let parsed_url = Url::parse(&link).map_err(|e| e.to_string())?;
|
let parsed_url = Url::parse(&link).map_err(|e| e.to_string())?;
|
||||||
let scheme = parsed_url.scheme();
|
let scheme = parsed_url.scheme();
|
||||||
let proxy_name = parsed_url.fragment()
|
let proxy_name = parsed_url
|
||||||
|
.fragment()
|
||||||
.map(|f| percent_decode_str(f).decode_utf8_lossy().to_string())
|
.map(|f| percent_decode_str(f).decode_utf8_lossy().to_string())
|
||||||
.unwrap_or_else(|| "Proxy from Link".to_string());
|
.unwrap_or_else(|| "Proxy from Link".to_string());
|
||||||
|
|
||||||
let mut proxy_map: BTreeMap<String, Value> = BTreeMap::new();
|
let mut proxy_map: BTreeMap<String, Value> = BTreeMap::new();
|
||||||
proxy_map.insert("name".into(), proxy_name.clone().into());
|
proxy_map.insert("name".into(), proxy_name.clone().into());
|
||||||
proxy_map.insert("type".into(), scheme.into());
|
proxy_map.insert("type".into(), scheme.into());
|
||||||
proxy_map.insert("server".into(), parsed_url.host_str().unwrap_or_default().into());
|
proxy_map.insert(
|
||||||
|
"server".into(),
|
||||||
|
parsed_url.host_str().unwrap_or_default().into(),
|
||||||
|
);
|
||||||
proxy_map.insert("port".into(), parsed_url.port().unwrap_or(443).into());
|
proxy_map.insert("port".into(), parsed_url.port().unwrap_or(443).into());
|
||||||
proxy_map.insert("udp".into(), true.into());
|
proxy_map.insert("udp".into(), true.into());
|
||||||
|
|
||||||
@@ -1130,16 +1181,29 @@ pub async fn create_profile_from_share_link(link: String, template_name: String)
|
|||||||
"security" if value == "tls" => {
|
"security" if value == "tls" => {
|
||||||
proxy_map.insert("tls".into(), true.into());
|
proxy_map.insert("tls".into(), true.into());
|
||||||
}
|
}
|
||||||
"flow" => { proxy_map.insert("flow".into(), value.to_string().into()); }
|
"flow" => {
|
||||||
"sni" => { proxy_map.insert("servername".into(), value.to_string().into()); }
|
proxy_map.insert("flow".into(), value.to_string().into());
|
||||||
"fp" => { proxy_map.insert("client-fingerprint".into(), value.to_string().into()); }
|
}
|
||||||
"pbk" => { reality_opts.insert("public-key".into(), value.to_string().into()); }
|
"sni" => {
|
||||||
"sid" => { reality_opts.insert("short-id".into(), value.to_string().into()); }
|
proxy_map.insert("servername".into(), value.to_string().into());
|
||||||
|
}
|
||||||
|
"fp" => {
|
||||||
|
proxy_map.insert("client-fingerprint".into(), value.to_string().into());
|
||||||
|
}
|
||||||
|
"pbk" => {
|
||||||
|
reality_opts.insert("public-key".into(), value.to_string().into());
|
||||||
|
}
|
||||||
|
"sid" => {
|
||||||
|
reality_opts.insert("short-id".into(), value.to_string().into());
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !reality_opts.is_empty() {
|
if !reality_opts.is_empty() {
|
||||||
proxy_map.insert("reality-opts".into(), serde_yaml::to_value(reality_opts).map_err(|e| e.to_string())?);
|
proxy_map.insert(
|
||||||
|
"reality-opts".into(),
|
||||||
|
serde_yaml::to_value(reality_opts).map_err(|e| e.to_string())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"ss" => {
|
"ss" => {
|
||||||
@@ -1155,19 +1219,32 @@ pub async fn create_profile_from_share_link(link: String, template_name: String)
|
|||||||
"vmess" => {
|
"vmess" => {
|
||||||
if let Ok(decoded_bytes) = STANDARD.decode(parsed_url.host_str().unwrap_or_default()) {
|
if let Ok(decoded_bytes) = STANDARD.decode(parsed_url.host_str().unwrap_or_default()) {
|
||||||
if let Ok(json_str) = String::from_utf8(decoded_bytes) {
|
if let Ok(json_str) = String::from_utf8(decoded_bytes) {
|
||||||
if let Ok(vmess_params) = serde_json::from_str::<BTreeMap<String, Value>>(&json_str) {
|
if let Ok(vmess_params) =
|
||||||
if let Some(add) = vmess_params.get("add") { proxy_map.insert("server".into(), add.clone()); }
|
serde_json::from_str::<BTreeMap<String, Value>>(&json_str)
|
||||||
if let Some(port) = vmess_params.get("port") { proxy_map.insert("port".into(), port.clone()); }
|
{
|
||||||
if let Some(id) = vmess_params.get("id") { proxy_map.insert("uuid".into(), id.clone()); }
|
if let Some(add) = vmess_params.get("add") {
|
||||||
if let Some(aid) = vmess_params.get("aid") { proxy_map.insert("alterId".into(), aid.clone()); }
|
proxy_map.insert("server".into(), add.clone());
|
||||||
if let Some(net) = vmess_params.get("net") { proxy_map.insert("network".into(), net.clone()); }
|
}
|
||||||
if let Some(ps) = vmess_params.get("ps") { proxy_map.insert("name".into(), ps.clone()); }
|
if let Some(port) = vmess_params.get("port") {
|
||||||
|
proxy_map.insert("port".into(), port.clone());
|
||||||
|
}
|
||||||
|
if let Some(id) = vmess_params.get("id") {
|
||||||
|
proxy_map.insert("uuid".into(), id.clone());
|
||||||
|
}
|
||||||
|
if let Some(aid) = vmess_params.get("aid") {
|
||||||
|
proxy_map.insert("alterId".into(), aid.clone());
|
||||||
|
}
|
||||||
|
if let Some(net) = vmess_params.get("net") {
|
||||||
|
proxy_map.insert("network".into(), net.clone());
|
||||||
|
}
|
||||||
|
if let Some(ps) = vmess_params.get("ps") {
|
||||||
|
proxy_map.insert("name".into(), ps.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut config: Value = serde_yaml::from_str(template_yaml).map_err(|e| e.to_string())?;
|
let mut config: Value = serde_yaml::from_str(template_yaml).map_err(|e| e.to_string())?;
|
||||||
@@ -1177,10 +1254,15 @@ pub async fn create_profile_from_share_link(link: String, template_name: String)
|
|||||||
proxies.push(serde_yaml::to_value(proxy_map).map_err(|e| e.to_string())?);
|
proxies.push(serde_yaml::to_value(proxy_map).map_err(|e| e.to_string())?);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(groups) = config.get_mut("proxy-groups").and_then(|v| v.as_sequence_mut()) {
|
if let Some(groups) = config
|
||||||
|
.get_mut("proxy-groups")
|
||||||
|
.and_then(|v| v.as_sequence_mut())
|
||||||
|
{
|
||||||
for group in groups.iter_mut() {
|
for group in groups.iter_mut() {
|
||||||
if let Some(mapping) = group.as_mapping_mut() {
|
if let Some(mapping) = group.as_mapping_mut() {
|
||||||
if let Some(proxies_list) = mapping.get_mut("proxies").and_then(|p| p.as_sequence_mut()) {
|
if let Some(proxies_list) =
|
||||||
|
mapping.get_mut("proxies").and_then(|p| p.as_sequence_mut())
|
||||||
|
{
|
||||||
let new_proxies_list: Vec<Value> = proxies_list
|
let new_proxies_list: Vec<Value> = proxies_list
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
@@ -1199,8 +1281,13 @@ pub async fn create_profile_from_share_link(link: String, template_name: String)
|
|||||||
|
|
||||||
let new_yaml_content = serde_yaml::to_string(&config).map_err(|e| e.to_string())?;
|
let new_yaml_content = serde_yaml::to_string(&config).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
let item = PrfItem::from_local(proxy_name, "Created from share link".into(), Some(new_yaml_content), None)
|
let item = PrfItem::from_local(
|
||||||
.map_err(|e| e.to_string())?;
|
proxy_name,
|
||||||
|
"Created from share link".into(),
|
||||||
|
Some(new_yaml_content),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
wrap_err!(Config::profiles().data().append_item(item))
|
wrap_err!(Config::profiles().data().append_item(item))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ impl PrfItem {
|
|||||||
if let Ok(mut parsed_url) = Url::parse(url) {
|
if let Ok(mut parsed_url) = Url::parse(url) {
|
||||||
if parsed_url.set_host(Some(new_domain)).is_ok() {
|
if parsed_url.set_host(Some(new_domain)).is_ok() {
|
||||||
final_url = parsed_url.to_string();
|
final_url = parsed_url.to_string();
|
||||||
log::info!(target: "app", "URL host updated to -> {}", final_url);
|
log::info!(target: "app", "URL host updated to -> {final_url}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -340,10 +340,12 @@ impl IVerge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)).unwrap_or_else(|err| {
|
dirs::verge_path()
|
||||||
log::error!(target: "app", "{err}");
|
.and_then(|path| help::read_yaml::<IVerge>(&path))
|
||||||
Self::template()
|
.unwrap_or_else(|err| {
|
||||||
})
|
log::error!(target: "app", "{err}");
|
||||||
|
Self::template()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn template() -> Self {
|
pub fn template() -> Self {
|
||||||
|
|||||||
@@ -153,7 +153,12 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
/// 验证运行时配置
|
/// 验证运行时配置
|
||||||
pub async fn validate_config(&self) -> Result<(bool, String)> {
|
pub async fn validate_config(&self) -> Result<(bool, String)> {
|
||||||
logging!(info, Type::Config, true, "Generate temporary config file for validation");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Generate temporary config file for validation"
|
||||||
|
);
|
||||||
let config_path = Config::generate_file(ConfigType::Check)?;
|
let config_path = Config::generate_file(ConfigType::Check)?;
|
||||||
let config_path = dirs::path_to_str(&config_path)?;
|
let config_path = dirs::path_to_str(&config_path)?;
|
||||||
self.validate_config_internal(config_path).await
|
self.validate_config_internal(config_path).await
|
||||||
@@ -166,7 +171,12 @@ impl CoreManager {
|
|||||||
) -> Result<(bool, String)> {
|
) -> Result<(bool, String)> {
|
||||||
// 检查程序是否正在退出,如果是则跳过验证
|
// 检查程序是否正在退出,如果是则跳过验证
|
||||||
if handle::Handle::global().is_exiting() {
|
if handle::Handle::global().is_exiting() {
|
||||||
logging!(info, Type::Core, true, "App is exiting, skipping validation");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"App is exiting, skipping validation"
|
||||||
|
);
|
||||||
return Ok((true, String::new()));
|
return Ok((true, String::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +245,12 @@ impl CoreManager {
|
|||||||
async fn validate_config_internal(&self, config_path: &str) -> Result<(bool, String)> {
|
async fn validate_config_internal(&self, config_path: &str) -> Result<(bool, String)> {
|
||||||
// 检查程序是否正在退出,如果是则跳过验证
|
// 检查程序是否正在退出,如果是则跳过验证
|
||||||
if handle::Handle::global().is_exiting() {
|
if handle::Handle::global().is_exiting() {
|
||||||
logging!(info, Type::Core, true, "App is exiting, skipping validation");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"App is exiting, skipping validation"
|
||||||
|
);
|
||||||
return Ok((true, String::new()));
|
return Ok((true, String::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +268,13 @@ impl CoreManager {
|
|||||||
let app_handle = handle::Handle::global().app_handle().unwrap();
|
let app_handle = handle::Handle::global().app_handle().unwrap();
|
||||||
let app_dir = dirs::app_home_dir()?;
|
let app_dir = dirs::app_home_dir()?;
|
||||||
let app_dir_str = dirs::path_to_str(&app_dir)?;
|
let app_dir_str = dirs::path_to_str(&app_dir)?;
|
||||||
logging!(info, Type::Config, true, "Validation directory: {}", app_dir_str);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Validation directory: {}",
|
||||||
|
app_dir_str
|
||||||
|
);
|
||||||
|
|
||||||
// 使用子进程运行clash验证配置
|
// 使用子进程运行clash验证配置
|
||||||
let output = app_handle
|
let output = app_handle
|
||||||
@@ -271,14 +292,24 @@ impl CoreManager {
|
|||||||
let has_error =
|
let has_error =
|
||||||
!output.status.success() || error_keywords.iter().any(|&kw| stderr.contains(kw));
|
!output.status.success() || error_keywords.iter().any(|&kw| stderr.contains(kw));
|
||||||
|
|
||||||
logging!(info, Type::Config, true, "-------- Validation Result --------");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"-------- Validation Result --------"
|
||||||
|
);
|
||||||
|
|
||||||
if !stderr.is_empty() {
|
if !stderr.is_empty() {
|
||||||
logging!(info, Type::Config, true, "stderr output:\n{}", stderr);
|
logging!(info, Type::Config, true, "stderr output:\n{}", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_error {
|
if has_error {
|
||||||
logging!(info, Type::Config, true, "Errors found, processing error details");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Errors found, processing error details"
|
||||||
|
);
|
||||||
let error_msg = if !stdout.is_empty() {
|
let error_msg = if !stdout.is_empty() {
|
||||||
stdout.to_string()
|
stdout.to_string()
|
||||||
} else if !stderr.is_empty() {
|
} else if !stderr.is_empty() {
|
||||||
@@ -299,14 +330,26 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
/// 只进行文件语法检查,不进行完整验证
|
/// 只进行文件语法检查,不进行完整验证
|
||||||
async fn validate_file_syntax(&self, config_path: &str) -> Result<(bool, String)> {
|
async fn validate_file_syntax(&self, config_path: &str) -> Result<(bool, String)> {
|
||||||
logging!(info, Type::Config, true, "Starting file check: {}", config_path);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Starting file check: {}",
|
||||||
|
config_path
|
||||||
|
);
|
||||||
|
|
||||||
// 读取文件内容
|
// 读取文件内容
|
||||||
let content = match std::fs::read_to_string(config_path) {
|
let content = match std::fs::read_to_string(config_path) {
|
||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let error_msg = format!("Failed to read file: {err}");
|
let error_msg = format!("Failed to read file: {err}");
|
||||||
logging!(error, Type::Config, true, "Failed to read file: {}", error_msg);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Failed to read file: {}",
|
||||||
|
error_msg
|
||||||
|
);
|
||||||
return Ok((false, error_msg));
|
return Ok((false, error_msg));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -320,7 +363,13 @@ impl CoreManager {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
// 使用标准化的前缀,以便错误处理函数能正确识别
|
// 使用标准化的前缀,以便错误处理函数能正确识别
|
||||||
let error_msg = format!("YAML syntax error: {err}");
|
let error_msg = format!("YAML syntax error: {err}");
|
||||||
logging!(error, Type::Config, true, "YAML syntax error: {}", error_msg);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"YAML syntax error: {}",
|
||||||
|
error_msg
|
||||||
|
);
|
||||||
Ok((false, error_msg))
|
Ok((false, error_msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,7 +387,13 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
logging!(debug, Type::Config, true, "Validating script file: {}", path);
|
logging!(
|
||||||
|
debug,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Validating script file: {}",
|
||||||
|
path
|
||||||
|
);
|
||||||
|
|
||||||
// 使用boa引擎进行基本语法检查
|
// 使用boa引擎进行基本语法检查
|
||||||
use boa_engine::{Context, Source};
|
use boa_engine::{Context, Source};
|
||||||
@@ -348,7 +403,13 @@ impl CoreManager {
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
logging!(debug, Type::Config, true, "Script syntax validation passed: {}", path);
|
logging!(
|
||||||
|
debug,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Script syntax validation passed: {}",
|
||||||
|
path
|
||||||
|
);
|
||||||
|
|
||||||
// 检查脚本是否包含main函数
|
// 检查脚本是否包含main函数
|
||||||
if !content.contains("function main")
|
if !content.contains("function main")
|
||||||
@@ -356,7 +417,13 @@ impl CoreManager {
|
|||||||
&& !content.contains("let main")
|
&& !content.contains("let main")
|
||||||
{
|
{
|
||||||
let error_msg = "Script must contain a main function";
|
let error_msg = "Script must contain a main function";
|
||||||
logging!(warn, Type::Config, true, "Script missing main function: {}", path);
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Script missing main function: {}",
|
||||||
|
path
|
||||||
|
);
|
||||||
//handle::Handle::notice_message("config_validate::script_missing_main", error_msg);
|
//handle::Handle::notice_message("config_validate::script_missing_main", error_msg);
|
||||||
return Ok((false, error_msg.to_string()));
|
return Ok((false, error_msg.to_string()));
|
||||||
}
|
}
|
||||||
@@ -375,14 +442,24 @@ impl CoreManager {
|
|||||||
pub async fn update_config(&self) -> Result<(bool, String)> {
|
pub async fn update_config(&self) -> Result<(bool, String)> {
|
||||||
// 检查程序是否正在退出,如果是则跳过完整验证流程
|
// 检查程序是否正在退出,如果是则跳过完整验证流程
|
||||||
if handle::Handle::global().is_exiting() {
|
if handle::Handle::global().is_exiting() {
|
||||||
logging!(info, Type::Config, true, "App is exiting, skipping validation");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"App is exiting, skipping validation"
|
||||||
|
);
|
||||||
return Ok((true, String::new()));
|
return Ok((true, String::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
logging!(info, Type::Config, true, "Starting config update");
|
logging!(info, Type::Config, true, "Starting config update");
|
||||||
|
|
||||||
// 1. 先生成新的配置内容
|
// 1. 先生成新的配置内容
|
||||||
logging!(info, Type::Config, true, "Generating new configuration content");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Generating new configuration content"
|
||||||
|
);
|
||||||
Config::generate().await?;
|
Config::generate().await?;
|
||||||
|
|
||||||
// 2. 验证配置
|
// 2. 验证配置
|
||||||
@@ -396,12 +473,24 @@ impl CoreManager {
|
|||||||
Ok((true, "something".into()))
|
Ok((true, "something".into()))
|
||||||
}
|
}
|
||||||
Ok((false, error_msg)) => {
|
Ok((false, error_msg)) => {
|
||||||
logging!(warn, Type::Config, true, "Configuration validation failed: {}", error_msg);
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Configuration validation failed: {}",
|
||||||
|
error_msg
|
||||||
|
);
|
||||||
Config::runtime().discard();
|
Config::runtime().discard();
|
||||||
Ok((false, error_msg))
|
Ok((false, error_msg))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(warn, Type::Config, true, "Error occurred during validation: {}", e);
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"Error occurred during validation: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
Config::runtime().discard();
|
Config::runtime().discard();
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
@@ -435,7 +524,12 @@ impl CoreManager {
|
|||||||
impl CoreManager {
|
impl CoreManager {
|
||||||
/// 清理多余的 mihomo 进程
|
/// 清理多余的 mihomo 进程
|
||||||
async fn cleanup_orphaned_mihomo_processes(&self) -> Result<()> {
|
async fn cleanup_orphaned_mihomo_processes(&self) -> Result<()> {
|
||||||
logging!(info, Type::Core, true, "Starting cleanup of orphaned mihomo processes");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Starting cleanup of orphaned mihomo processes"
|
||||||
|
);
|
||||||
|
|
||||||
// 获取当前管理的进程 PID
|
// 获取当前管理的进程 PID
|
||||||
let current_pid = {
|
let current_pid = {
|
||||||
@@ -482,13 +576,24 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(debug, Type::Core, true, "Error occurred while finding processes: {}", e);
|
logging!(
|
||||||
|
debug,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Error occurred while finding processes: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pids_to_kill.is_empty() {
|
if pids_to_kill.is_empty() {
|
||||||
logging!(debug, Type::Core, true, "No orphaned mihomo processes found");
|
logging!(
|
||||||
|
debug,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"No orphaned mihomo processes found"
|
||||||
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,7 +942,12 @@ impl CoreManager {
|
|||||||
// 当服务安装失败时的回退逻辑
|
// 当服务安装失败时的回退逻辑
|
||||||
async fn attempt_service_init(&self) -> Result<()> {
|
async fn attempt_service_init(&self) -> Result<()> {
|
||||||
if service::check_service_needs_reinstall().await {
|
if service::check_service_needs_reinstall().await {
|
||||||
logging!(info, Type::Core, true, "Service version mismatch or abnormal status, performing reinstallation");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Service version mismatch or abnormal status, performing reinstallation"
|
||||||
|
);
|
||||||
if let Err(e) = service::reinstall_service().await {
|
if let Err(e) = service::reinstall_service().await {
|
||||||
logging!(
|
logging!(
|
||||||
warn,
|
warn,
|
||||||
@@ -849,7 +959,12 @@ impl CoreManager {
|
|||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
// 如果重装成功,还需要尝试启动服务
|
// 如果重装成功,还需要尝试启动服务
|
||||||
logging!(info, Type::Core, true, "Service reinstalled successfully, attempting to start");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Service reinstalled successfully, attempting to start"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = self.start_core_by_service().await {
|
if let Err(e) = self.start_core_by_service().await {
|
||||||
@@ -905,7 +1020,12 @@ impl CoreManager {
|
|||||||
);
|
);
|
||||||
match self.attempt_service_init().await {
|
match self.attempt_service_init().await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
logging!(info, Type::Core, true, "Service mode successfully started core");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Service mode successfully started core"
|
||||||
|
);
|
||||||
core_started_successfully = true;
|
core_started_successfully = true;
|
||||||
}
|
}
|
||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
@@ -957,16 +1077,31 @@ impl CoreManager {
|
|||||||
);
|
);
|
||||||
match service::install_service().await {
|
match service::install_service().await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
logging!(info, Type::Core, true, "Service installed successfully (first attempt)");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Service installed successfully (first attempt)"
|
||||||
|
);
|
||||||
let mut new_state = service::ServiceState::default();
|
let mut new_state = service::ServiceState::default();
|
||||||
new_state.record_install();
|
new_state.record_install();
|
||||||
new_state.prefer_sidecar = false;
|
new_state.prefer_sidecar = false;
|
||||||
new_state.save()?;
|
new_state.save()?;
|
||||||
|
|
||||||
if service::is_service_available().await.is_ok() {
|
if service::is_service_available().await.is_ok() {
|
||||||
logging!(info, Type::Core, true, "Newly installed service available; attempting to start");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Newly installed service available; attempting to start"
|
||||||
|
);
|
||||||
if self.start_core_by_service().await.is_ok() {
|
if self.start_core_by_service().await.is_ok() {
|
||||||
logging!(info, Type::Core, true, "Newly installed service started successfully");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Newly installed service started successfully"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
logging!(
|
logging!(
|
||||||
warn,
|
warn,
|
||||||
@@ -976,9 +1111,8 @@ impl CoreManager {
|
|||||||
);
|
);
|
||||||
let mut final_state = service::ServiceState::get();
|
let mut final_state = service::ServiceState::get();
|
||||||
final_state.prefer_sidecar = true;
|
final_state.prefer_sidecar = true;
|
||||||
final_state.last_error = Some(
|
final_state.last_error =
|
||||||
"Newly installed service failed to start".to_string(),
|
Some("Newly installed service failed to start".to_string());
|
||||||
);
|
|
||||||
final_state.save()?;
|
final_state.save()?;
|
||||||
self.start_core_by_sidecar().await?;
|
self.start_core_by_sidecar().await?;
|
||||||
}
|
}
|
||||||
@@ -1000,7 +1134,13 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
logging!(warn, Type::Core, true, "Service first-time installation failed: {}", err);
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Service first-time installation failed: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
let new_state = service::ServiceState {
|
let new_state = service::ServiceState {
|
||||||
last_error: Some(err.to_string()),
|
last_error: Some(err.to_string()),
|
||||||
prefer_sidecar: true,
|
prefer_sidecar: true,
|
||||||
@@ -1063,7 +1203,12 @@ impl CoreManager {
|
|||||||
if service::check_service_needs_reinstall().await {
|
if service::check_service_needs_reinstall().await {
|
||||||
service::reinstall_service().await?;
|
service::reinstall_service().await?;
|
||||||
}
|
}
|
||||||
logging!(info, Type::Core, true, "Service available; starting in service mode");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Service available; starting in service mode"
|
||||||
|
);
|
||||||
self.start_core_by_service().await?;
|
self.start_core_by_service().await?;
|
||||||
} else {
|
} else {
|
||||||
// 服务不可用,检查用户偏好
|
// 服务不可用,检查用户偏好
|
||||||
@@ -1077,7 +1222,12 @@ impl CoreManager {
|
|||||||
);
|
);
|
||||||
self.start_core_by_sidecar().await?;
|
self.start_core_by_sidecar().await?;
|
||||||
} else {
|
} else {
|
||||||
logging!(info, Type::Core, true, "Service unavailable; starting in Sidecar mode");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"Service unavailable; starting in Sidecar mode"
|
||||||
|
);
|
||||||
self.start_core_by_sidecar().await?;
|
self.start_core_by_sidecar().await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ pub async fn reinstall_service() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let error = format!("failed to install service: {}", err);
|
let error = format!("failed to install service: {err}");
|
||||||
service_state.last_error = Some(error.clone());
|
service_state.last_error = Some(error.clone());
|
||||||
service_state.prefer_sidecar = true;
|
service_state.prefer_sidecar = true;
|
||||||
service_state.save()?;
|
service_state.save()?;
|
||||||
@@ -477,7 +477,12 @@ pub async fn reinstall_service() -> Result<()> {
|
|||||||
|
|
||||||
/// 检查服务状态 - 使用IPC通信
|
/// 检查服务状态 - 使用IPC通信
|
||||||
pub async fn check_ipc_service_status() -> Result<JsonResponse> {
|
pub async fn check_ipc_service_status() -> Result<JsonResponse> {
|
||||||
logging!(info, Type::Service, true, "Starting service status check (IPC)");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Starting service status check (IPC)"
|
||||||
|
);
|
||||||
|
|
||||||
// 使用IPC通信
|
// 使用IPC通信
|
||||||
let payload = serde_json::json!({});
|
let payload = serde_json::json!({});
|
||||||
@@ -498,7 +503,13 @@ pub async fn check_ipc_service_status() -> Result<JsonResponse> {
|
|||||||
let err_msg = response
|
let err_msg = response
|
||||||
.error
|
.error
|
||||||
.unwrap_or_else(|| "Unknown service error".to_string());
|
.unwrap_or_else(|| "Unknown service error".to_string());
|
||||||
logging!(error, Type::Service, true, "Service response error: {}", err_msg);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Service response error: {}",
|
||||||
|
err_msg
|
||||||
|
);
|
||||||
bail!(err_msg);
|
bail!(err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,7 +590,13 @@ pub async fn check_ipc_service_status() -> Result<JsonResponse> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "IPC communication failed: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"IPC communication failed: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
bail!("Unable to connect to Koala Clash Service: {}", e)
|
bail!("Unable to connect to Koala Clash Service: {}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -587,7 +604,12 @@ pub async fn check_ipc_service_status() -> Result<JsonResponse> {
|
|||||||
|
|
||||||
/// 检查服务版本 - 使用IPC通信
|
/// 检查服务版本 - 使用IPC通信
|
||||||
pub async fn check_service_version() -> Result<String> {
|
pub async fn check_service_version() -> Result<String> {
|
||||||
logging!(info, Type::Service, true, "Starting service version check (IPC)");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Starting service version check (IPC)"
|
||||||
|
);
|
||||||
|
|
||||||
let payload = serde_json::json!({});
|
let payload = serde_json::json!({});
|
||||||
// logging!(debug, Type::Service, true, "发送GetVersion请求");
|
// logging!(debug, Type::Service, true, "发送GetVersion请求");
|
||||||
@@ -607,7 +629,13 @@ pub async fn check_service_version() -> Result<String> {
|
|||||||
let err_msg = response
|
let err_msg = response
|
||||||
.error
|
.error
|
||||||
.unwrap_or_else(|| "Failed to get service version".to_string());
|
.unwrap_or_else(|| "Failed to get service version".to_string());
|
||||||
logging!(error, Type::Service, true, "Failed to get service version: {}", err_msg);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to get service version: {}",
|
||||||
|
err_msg
|
||||||
|
);
|
||||||
bail!(err_msg);
|
bail!(err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +696,13 @@ pub async fn check_service_version() -> Result<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "IPC communication failed: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"IPC communication failed: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
bail!("Unable to connect to Koala Clash Service: {}", e)
|
bail!("Unable to connect to Koala Clash Service: {}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,7 +710,12 @@ pub async fn check_service_version() -> Result<String> {
|
|||||||
|
|
||||||
/// 检查服务是否需要重装
|
/// 检查服务是否需要重装
|
||||||
pub async fn check_service_needs_reinstall() -> bool {
|
pub async fn check_service_needs_reinstall() -> bool {
|
||||||
logging!(info, Type::Service, true, "Checking whether service needs reinstallation");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Checking whether service needs reinstallation"
|
||||||
|
);
|
||||||
|
|
||||||
let service_state = ServiceState::get();
|
let service_state = ServiceState::get();
|
||||||
|
|
||||||
@@ -701,7 +740,12 @@ pub async fn check_service_needs_reinstall() -> bool {
|
|||||||
let needs_reinstall = version != REQUIRED_SERVICE_VERSION;
|
let needs_reinstall = version != REQUIRED_SERVICE_VERSION;
|
||||||
if needs_reinstall {
|
if needs_reinstall {
|
||||||
log::warn!(target: "app", "Service version mismatch detected, reinstallation required! current={version}, required={REQUIRED_SERVICE_VERSION}");
|
log::warn!(target: "app", "Service version mismatch detected, reinstallation required! current={version}, required={REQUIRED_SERVICE_VERSION}");
|
||||||
logging!(warn, Type::Service, true, "Service version mismatch, reinstallation required");
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Service version mismatch, reinstallation required"
|
||||||
|
);
|
||||||
|
|
||||||
// log::debug!(target: "app", "当前版本字节: {:?}", version.as_bytes());
|
// log::debug!(target: "app", "当前版本字节: {:?}", version.as_bytes());
|
||||||
// log::debug!(target: "app", "要求版本字节: {:?}", REQUIRED_SERVICE_VERSION.as_bytes());
|
// log::debug!(target: "app", "要求版本字节: {:?}", REQUIRED_SERVICE_VERSION.as_bytes());
|
||||||
@@ -713,7 +757,13 @@ pub async fn check_service_needs_reinstall() -> bool {
|
|||||||
needs_reinstall
|
needs_reinstall
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
logging!(error, Type::Service, true, "Failed to check service version: {}", err);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to check service version: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
|
||||||
// 检查服务是否可用
|
// 检查服务是否可用
|
||||||
match is_service_available().await {
|
match is_service_available().await {
|
||||||
@@ -783,8 +833,16 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
|
|||||||
); */
|
); */
|
||||||
|
|
||||||
if !response.success {
|
if !response.success {
|
||||||
let err_msg = response.error.unwrap_or_else(|| "Failed to start core".to_string());
|
let err_msg = response
|
||||||
logging!(error, Type::Service, true, "Failed to start core: {}", err_msg);
|
.error
|
||||||
|
.unwrap_or_else(|| "Failed to start core".to_string());
|
||||||
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to start core: {}",
|
||||||
|
err_msg
|
||||||
|
);
|
||||||
bail!(err_msg);
|
bail!(err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,11 +869,22 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logging!(info, Type::Service, true, "Service successfully started core");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Service successfully started core"
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Failed to start core via IPC: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to start core via IPC: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
bail!("Unable to connect to Koala Clash Service: {}", e)
|
bail!("Unable to connect to Koala Clash Service: {}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -915,7 +984,9 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
|
|||||||
.context("Unable to connect to Koala Clash Service")?;
|
.context("Unable to connect to Koala Clash Service")?;
|
||||||
|
|
||||||
if !response.success {
|
if !response.success {
|
||||||
bail!(response.error.unwrap_or_else(|| "Failed to stop core".to_string()));
|
bail!(response
|
||||||
|
.error
|
||||||
|
.unwrap_or_else(|| "Failed to stop core".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(data) = &response.data {
|
if let Some(data) = &response.data {
|
||||||
@@ -945,7 +1016,12 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
|
|||||||
|
|
||||||
/// 检查服务是否正在运行
|
/// 检查服务是否正在运行
|
||||||
pub async fn is_service_available() -> Result<()> {
|
pub async fn is_service_available() -> Result<()> {
|
||||||
logging!(info, Type::Service, true, "Checking whether service is running");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Checking whether service is running"
|
||||||
|
);
|
||||||
|
|
||||||
match check_ipc_service_status().await {
|
match check_ipc_service_status().await {
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
@@ -965,7 +1041,13 @@ pub async fn is_service_available() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
logging!(error, Type::Service, true, "Failed to check service running status: {}", err);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to check service running status: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,14 +129,25 @@ pub async fn send_ipc_request(
|
|||||||
winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE},
|
winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE},
|
||||||
};
|
};
|
||||||
|
|
||||||
logging!(info, Type::Service, true, "Connecting to service (Windows)...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Connecting to service (Windows)..."
|
||||||
|
);
|
||||||
|
|
||||||
let command_type = format!("{:?}", command);
|
let command_type = format!("{:?}", command);
|
||||||
|
|
||||||
let request = match create_signed_request(command, payload) {
|
let request = match create_signed_request(command, payload) {
|
||||||
Ok(req) => req,
|
Ok(req) => req,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Failed to create signed request: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to create signed request: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -147,7 +158,13 @@ pub async fn send_ipc_request(
|
|||||||
let c_pipe_name = match CString::new(IPC_SOCKET_NAME) {
|
let c_pipe_name = match CString::new(IPC_SOCKET_NAME) {
|
||||||
Ok(name) => name,
|
Ok(name) => name,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Failed to create CString: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to create CString: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("Failed to create CString: {}", e));
|
return Err(anyhow::anyhow!("Failed to create CString: {}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -177,18 +194,35 @@ pub async fn send_ipc_request(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut pipe = unsafe { File::from_raw_handle(handle as RawHandle) };
|
let mut pipe = unsafe { File::from_raw_handle(handle as RawHandle) };
|
||||||
logging!(info, Type::Service, true, "Service connection successful (Windows)");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Service connection successful (Windows)"
|
||||||
|
);
|
||||||
|
|
||||||
let request_bytes = request_json.as_bytes();
|
let request_bytes = request_json.as_bytes();
|
||||||
let len_bytes = (request_bytes.len() as u32).to_be_bytes();
|
let len_bytes = (request_bytes.len() as u32).to_be_bytes();
|
||||||
|
|
||||||
if let Err(e) = pipe.write_all(&len_bytes) {
|
if let Err(e) = pipe.write_all(&len_bytes) {
|
||||||
logging!(error, Type::Service, true, "Failed to write request length: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to write request length: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("写入请求长度失败: {}", e));
|
return Err(anyhow::anyhow!("写入请求长度失败: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = pipe.write_all(request_bytes) {
|
if let Err(e) = pipe.write_all(request_bytes) {
|
||||||
logging!(error, Type::Service, true, "Failed to write request body: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to write request body: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("写入请求内容失败: {}", e));
|
return Err(anyhow::anyhow!("写入请求内容失败: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +233,13 @@ pub async fn send_ipc_request(
|
|||||||
|
|
||||||
let mut response_len_bytes = [0u8; 4];
|
let mut response_len_bytes = [0u8; 4];
|
||||||
if let Err(e) = pipe.read_exact(&mut response_len_bytes) {
|
if let Err(e) = pipe.read_exact(&mut response_len_bytes) {
|
||||||
logging!(error, Type::Service, true, "Failed to read response length: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to read response length: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("读取响应长度失败: {}", e));
|
return Err(anyhow::anyhow!("读取响应长度失败: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,14 +247,26 @@ pub async fn send_ipc_request(
|
|||||||
|
|
||||||
let mut response_bytes = vec![0u8; response_len];
|
let mut response_bytes = vec![0u8; response_len];
|
||||||
if let Err(e) = pipe.read_exact(&mut response_bytes) {
|
if let Err(e) = pipe.read_exact(&mut response_bytes) {
|
||||||
logging!(error, Type::Service, true, "Failed to read response body: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to read response body: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("读取响应内容失败: {}", e));
|
return Err(anyhow::anyhow!("读取响应内容失败: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
let response: IpcResponse = match serde_json::from_slice::<IpcResponse>(&response_bytes) {
|
let response: IpcResponse = match serde_json::from_slice::<IpcResponse>(&response_bytes) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Failed to parse service response: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to parse service response: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("解析响应失败: {}", e));
|
return Err(anyhow::anyhow!("解析响应失败: {}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -222,12 +274,23 @@ pub async fn send_ipc_request(
|
|||||||
match verify_response_signature(&response) {
|
match verify_response_signature(&response) {
|
||||||
Ok(valid) => {
|
Ok(valid) => {
|
||||||
if !valid {
|
if !valid {
|
||||||
logging!(error, Type::Service, true, "Service response signature verification failed");
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Service response signature verification failed"
|
||||||
|
);
|
||||||
bail!("服务响应签名验证失败");
|
bail!("服务响应签名验证失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Error verifying response signature: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Error verifying response signature: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,11 +334,22 @@ pub async fn send_ipc_request(
|
|||||||
|
|
||||||
let mut stream = match UnixStream::connect(IPC_SOCKET_NAME) {
|
let mut stream = match UnixStream::connect(IPC_SOCKET_NAME) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
logging!(info, Type::Service, true, "Service connection successful (Unix)");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Service connection successful (Unix)"
|
||||||
|
);
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Failed to connect to Unix socket: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to connect to Unix socket: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("无法连接到服务Unix套接字: {}", e));
|
return Err(anyhow::anyhow!("无法连接到服务Unix套接字: {}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -310,7 +384,13 @@ pub async fn send_ipc_request(
|
|||||||
let response: IpcResponse = match serde_json::from_slice::<IpcResponse>(&response_bytes) {
|
let response: IpcResponse = match serde_json::from_slice::<IpcResponse>(&response_bytes) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Failed to parse service response: {}", e,);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Failed to parse service response: {}",
|
||||||
|
e,
|
||||||
|
);
|
||||||
return Err(anyhow::anyhow!("解析响应失败: {}", e));
|
return Err(anyhow::anyhow!("解析响应失败: {}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -323,7 +403,13 @@ pub async fn send_ipc_request(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "Error verifying response signature: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Service,
|
||||||
|
true,
|
||||||
|
"Error verifying response signature: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,12 @@ impl Timer {
|
|||||||
let uid = item.uid.as_ref()?;
|
let uid = item.uid.as_ref()?;
|
||||||
|
|
||||||
if interval > 0 && cur_timestamp - updated >= interval * 60 {
|
if interval > 0 && cur_timestamp - updated >= interval * 60 {
|
||||||
logging!(info, Type::Timer, "Profile requires immediate update: uid={}", uid);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Timer,
|
||||||
|
"Profile requires immediate update: uid={}",
|
||||||
|
uid
|
||||||
|
);
|
||||||
Some(uid.clone())
|
Some(uid.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -321,7 +326,12 @@ impl Timer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logging!(debug, Type::Timer, "定时任务变更数量: {}", diff_map.len());
|
logging!(debug, Type::Timer, "定时任务变更数量: {}", diff_map.len());
|
||||||
logging!(debug, Type::Timer, "Number of timer task changes: {}", diff_map.len());
|
logging!(
|
||||||
|
debug,
|
||||||
|
Type::Timer,
|
||||||
|
"Number of timer task changes: {}",
|
||||||
|
diff_map.len()
|
||||||
|
);
|
||||||
diff_map
|
diff_map
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +380,12 @@ impl Timer {
|
|||||||
let task = match timer_map.get(uid) {
|
let task = match timer_map.get(uid) {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => {
|
None => {
|
||||||
logging!(warn, Type::Timer, "Corresponding timer task not found, uid={}", uid);
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Timer,
|
||||||
|
"Corresponding timer task not found, uid={}",
|
||||||
|
uid
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -389,7 +404,12 @@ impl Timer {
|
|||||||
let profile = match items.iter().find(|item| item.uid.as_deref() == Some(uid)) {
|
let profile = match items.iter().find(|item| item.uid.as_deref() == Some(uid)) {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
logging!(warn, Type::Timer, "Corresponding profile not found, uid={}", uid);
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Timer,
|
||||||
|
"Corresponding profile not found, uid={}",
|
||||||
|
uid
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use tauri::tray::TrayIconBuilder;
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub mod speed_rate;
|
pub mod speed_rate;
|
||||||
use crate::{
|
use crate::{
|
||||||
cmd,
|
|
||||||
config::Config,
|
config::Config,
|
||||||
feat, logging,
|
feat, logging,
|
||||||
module::{lightweight::is_in_lightweight_mode, mihomo::Rate},
|
module::{lightweight::is_in_lightweight_mode, mihomo::Rate},
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
|||||||
.filter(|(s, _)| s.is_support(clash_core.as_ref()))
|
.filter(|(s, _)| s.is_support(clash_core.as_ref()))
|
||||||
.map(|(_, c)| c)
|
.map(|(_, c)| c)
|
||||||
.for_each(|item| {
|
.for_each(|item| {
|
||||||
log::debug!(target: "app", "run builtin script {}", item.uid);
|
log::debug!(target: "app", "run builtin script {0}", item.uid);
|
||||||
if let ChainType::Script(script) = item.data {
|
if let ChainType::Script(script) = item.data {
|
||||||
match use_script(script, config.to_owned(), "".to_string()) {
|
match use_script(script, config.to_owned(), "".to_string()) {
|
||||||
Ok((res_config, _)) => {
|
Ok((res_config, _)) => {
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ fn test_script() {
|
|||||||
fn test_escape_unescape() {
|
fn test_escape_unescape() {
|
||||||
let test_string = r#"Hello "World"!\nThis is a test with \u00A9 copyright symbol."#;
|
let test_string = r#"Hello "World"!\nThis is a test with \u00A9 copyright symbol."#;
|
||||||
let escaped = escape_js_string_for_single_quote(test_string);
|
let escaped = escape_js_string_for_single_quote(test_string);
|
||||||
println!("Original: {}", test_string);
|
println!("Original: {test_string}");
|
||||||
println!("Escaped: {}", escaped);
|
println!("Escaped: {escaped}");
|
||||||
|
|
||||||
let json_str = r#"{"key":"value","nested":{"key":"value"}}"#;
|
let json_str = r#"{"key":"value","nested":{"key":"value"}}"#;
|
||||||
let parsed = parse_json_safely(json_str).unwrap();
|
let parsed = parse_json_safely(json_str).unwrap();
|
||||||
|
|||||||
@@ -31,7 +31,13 @@ pub async fn update_profile(
|
|||||||
option: Option<PrfOption>,
|
option: Option<PrfOption>,
|
||||||
auto_refresh: Option<bool>,
|
auto_refresh: Option<bool>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
logging!(info, Type::Config, true, "[Subscription Update] Start updating subscription {}", uid);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"[Subscription Update] Start updating subscription {}",
|
||||||
|
uid
|
||||||
|
);
|
||||||
let auto_refresh = auto_refresh.unwrap_or(true); // 默认为true,保持兼容性
|
let auto_refresh = auto_refresh.unwrap_or(true); // 默认为true,保持兼容性
|
||||||
|
|
||||||
let url_opt = {
|
let url_opt = {
|
||||||
@@ -131,14 +137,30 @@ pub async fn update_profile(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if should_update {
|
if should_update {
|
||||||
logging!(info, Type::Config, true, "[Subscription Update] Update core configuration");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"[Subscription Update] Update core configuration"
|
||||||
|
);
|
||||||
match CoreManager::global().update_config().await {
|
match CoreManager::global().update_config().await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
logging!(info, Type::Config, true, "[Subscription Update] Update succeeded");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"[Subscription Update] Update succeeded"
|
||||||
|
);
|
||||||
handle::Handle::refresh_clash();
|
handle::Handle::refresh_clash();
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
logging!(error, Type::Config, true, "[Subscription Update] Update failed: {}", err);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"[Subscription Update] Update failed: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
handle::Handle::notice_message("update_failed", format!("{err}"));
|
handle::Handle::notice_message("update_failed", format!("{err}"));
|
||||||
log::error!(target: "app", "{err}");
|
log::error!(target: "app", "{err}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,12 @@ pub fn quit() {
|
|||||||
|
|
||||||
// 使用异步任务处理资源清理,避免阻塞
|
// 使用异步任务处理资源清理,避免阻塞
|
||||||
AsyncHandler::spawn(move || async move {
|
AsyncHandler::spawn(move || async move {
|
||||||
logging!(info, Type::System, true, "Start asynchronous resource cleanup");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::System,
|
||||||
|
true,
|
||||||
|
"Start asynchronous resource cleanup"
|
||||||
|
);
|
||||||
let cleanup_result = clean_async().await;
|
let cleanup_result = clean_async().await;
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
@@ -95,7 +100,12 @@ pub fn quit() {
|
|||||||
async fn clean_async() -> bool {
|
async fn clean_async() -> bool {
|
||||||
use tokio::time::{timeout, Duration};
|
use tokio::time::{timeout, Duration};
|
||||||
|
|
||||||
logging!(info, Type::System, true, "Start executing asynchronous cleanup...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::System,
|
||||||
|
true,
|
||||||
|
"Start executing asynchronous cleanup..."
|
||||||
|
);
|
||||||
|
|
||||||
// 1. 处理TUN模式
|
// 1. 处理TUN模式
|
||||||
let tun_task = async {
|
let tun_task = async {
|
||||||
@@ -220,7 +230,13 @@ pub fn clean() -> bool {
|
|||||||
|
|
||||||
match rx.recv_timeout(std::time::Duration::from_secs(8)) {
|
match rx.recv_timeout(std::time::Duration::from_secs(8)) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
logging!(info, Type::System, true, "Cleanup completed, result: {}", result);
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::System,
|
||||||
|
true,
|
||||||
|
"Cleanup completed, result: {}",
|
||||||
|
result
|
||||||
|
);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
|||||||
@@ -144,7 +144,12 @@ pub fn run() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 窗口管理
|
// 窗口管理
|
||||||
logging!(info, Type::Setup, true, "Initializing window state management...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Setup,
|
||||||
|
true,
|
||||||
|
"Initializing window state management..."
|
||||||
|
);
|
||||||
let window_state_plugin = tauri_plugin_window_state::Builder::new()
|
let window_state_plugin = tauri_plugin_window_state::Builder::new()
|
||||||
.with_filename("window_state.json")
|
.with_filename("window_state.json")
|
||||||
.with_state_flags(tauri_plugin_window_state::StateFlags::default())
|
.with_state_flags(tauri_plugin_window_state::StateFlags::default())
|
||||||
@@ -154,7 +159,12 @@ pub fn run() {
|
|||||||
// 异步处理
|
// 异步处理
|
||||||
let app_handle = app.handle().clone();
|
let app_handle = app.handle().clone();
|
||||||
AsyncHandler::spawn(move || async move {
|
AsyncHandler::spawn(move || async move {
|
||||||
logging!(info, Type::Setup, true, "Executing app setup asynchronously...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Setup,
|
||||||
|
true,
|
||||||
|
"Executing app setup asynchronously..."
|
||||||
|
);
|
||||||
match timeout(
|
match timeout(
|
||||||
Duration::from_secs(30),
|
Duration::from_secs(30),
|
||||||
resolve::resolve_setup_async(&app_handle),
|
resolve::resolve_setup_async(&app_handle),
|
||||||
@@ -175,7 +185,12 @@ pub fn run() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
logging!(info, Type::Setup, true, "Executing main setup operations...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Setup,
|
||||||
|
true,
|
||||||
|
"Executing main setup operations..."
|
||||||
|
);
|
||||||
|
|
||||||
logging!(info, Type::Setup, true, "Initializing AppHandleManager...");
|
logging!(info, Type::Setup, true, "Initializing AppHandleManager...");
|
||||||
AppHandleManager::global().init(app.handle().clone());
|
AppHandleManager::global().init(app.handle().clone());
|
||||||
@@ -185,12 +200,24 @@ pub fn run() {
|
|||||||
|
|
||||||
logging!(info, Type::Setup, true, "Initializing config...");
|
logging!(info, Type::Setup, true, "Initializing config...");
|
||||||
if let Err(e) = utils::init::init_config() {
|
if let Err(e) = utils::init::init_config() {
|
||||||
logging!(error, Type::Setup, true, "Failed to initialize config: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Setup,
|
||||||
|
true,
|
||||||
|
"Failed to initialize config: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
logging!(info, Type::Setup, true, "Initializing resources...");
|
logging!(info, Type::Setup, true, "Initializing resources...");
|
||||||
if let Err(e) = utils::init::init_resources() {
|
if let Err(e) = utils::init::init_resources() {
|
||||||
logging!(error, Type::Setup, true, "Failed to initialize resources: {}", e);
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Setup,
|
||||||
|
true,
|
||||||
|
"Failed to initialize resources: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.manage(Mutex::new(state::proxy::CmdProxyState::default()));
|
app.manage(Mutex::new(state::proxy::CmdProxyState::default()));
|
||||||
@@ -198,13 +225,23 @@ pub fn run() {
|
|||||||
|
|
||||||
tauri::async_runtime::spawn(async {
|
tauri::async_runtime::spawn(async {
|
||||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||||
logging!(info, Type::Cmd, true, "Running profile updates at startup...");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Cmd,
|
||||||
|
true,
|
||||||
|
"Running profile updates at startup..."
|
||||||
|
);
|
||||||
if let Err(e) = crate::cmd::update_profiles_on_startup().await {
|
if let Err(e) = crate::cmd::update_profiles_on_startup().await {
|
||||||
log::error!("Failed to update profiles on startup: {}", e);
|
log::error!("Failed to update profiles on startup: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
logging!(info, Type::Setup, true, "Initialization completed, continuing");
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Setup,
|
||||||
|
true,
|
||||||
|
"Initialization completed, continuing"
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
@@ -376,7 +413,12 @@ pub fn run() {
|
|||||||
if let Some(window) = core::handle::Handle::global().get_window() {
|
if let Some(window) = core::handle::Handle::global().get_window() {
|
||||||
let _ = window.hide();
|
let _ = window.hide();
|
||||||
} else {
|
} else {
|
||||||
logging!(warn, Type::Window, true, "Tried to hide window but it does not exist");
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Window,
|
||||||
|
true,
|
||||||
|
"Tried to hide window but it does not exist"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tauri::WindowEvent::Focused(true) => {
|
tauri::WindowEvent::Focused(true) => {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ use tauri::{AppHandle, Manager};
|
|||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
use tauri::Url;
|
use tauri::Url;
|
||||||
use crate::config::PrfOption;
|
|
||||||
//#[cfg(not(target_os = "linux"))]
|
//#[cfg(not(target_os = "linux"))]
|
||||||
// use window_shadows::set_shadow;
|
// use window_shadows::set_shadow;
|
||||||
|
|
||||||
@@ -556,7 +555,9 @@ pub async fn resolve_scheme(param: String) -> Result<()> {
|
|||||||
for (key, value) in link_parsed.query_pairs() {
|
for (key, value) in link_parsed.query_pairs() {
|
||||||
match key.as_ref() {
|
match key.as_ref() {
|
||||||
"name" => name = Some(value.into_owned()),
|
"name" => name = Some(value.into_owned()),
|
||||||
"url" => url_param = Some(percent_decode_str(&value).decode_utf8_lossy().to_string()),
|
"url" => {
|
||||||
|
url_param = Some(percent_decode_str(&value).decode_utf8_lossy().to_string())
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user