Tunglies 0866b93175
feat(logging): introduce clash-verge-logging crate for management (#5486)
* feat(logging): introduce clash-verge-logging crate for management

- Added a new crate `clash-verge-logging` with dependencies on `log`, `tokio`, `compact_str`, and `flexi_logger`.
- Implemented logging types and macros for structured logging across the application.
- Replaced existing logging imports with the new `clash_verge_logging` crate in various modules.
- Updated logging functionality to support different logging types and error handling.
- Refactored code to improve logging consistency and maintainability.

* fix(logging): update import paths for clash_verge_logging in linux.rs and dns.rs

* fix(logging): update import statement for clash_verge_logging in windows.rs
2025-11-17 10:42:57 +08:00

147 lines
4.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::{
config::Config,
core::{CoreManager, handle, tray},
process::AsyncHandler,
utils::{self, resolve},
};
use clash_verge_logging::{Type, logging, logging_error};
use serde_yaml_ng::{Mapping, Value};
use smartstring::alias::String;
/// Restart the Clash core
pub async fn restart_clash_core() {
match CoreManager::global().restart_core().await {
Ok(_) => {
handle::Handle::refresh_clash();
handle::Handle::notice_message("set_config::ok", "ok");
}
Err(err) => {
handle::Handle::notice_message("set_config::error", format!("{err}"));
logging!(error, Type::Core, "{err}");
}
}
}
/// Restart the application
pub async fn restart_app() {
utils::server::shutdown_embedded_server();
if let Err(err) = resolve::resolve_reset_async().await {
handle::Handle::notice_message(
"restart_app::error",
format!("Failed to cleanup resources: {err}"),
);
logging!(error, Type::Core, "Restart failed during cleanup: {err}");
return;
}
let app_handle = handle::Handle::app_handle();
app_handle.restart();
}
fn after_change_clash_mode() {
AsyncHandler::spawn(move || async {
let mihomo = handle::Handle::mihomo().await;
match mihomo.get_connections().await {
Ok(connections) => {
if let Some(connections_array) = connections.connections {
for connection in connections_array {
let _ = mihomo.close_connection(&connection.id).await;
}
drop(mihomo);
}
}
Err(err) => {
logging!(error, Type::Core, "Failed to get connections: {err}");
}
}
});
}
/// Change Clash mode (rule/global/direct/script)
pub async fn change_clash_mode(mode: String) {
let mut mapping = Mapping::new();
mapping.insert(Value::from("mode"), Value::from(mode.as_str()));
// Convert YAML mapping to JSON Value
let json_value = serde_json::json!({
"mode": mode
});
logging!(debug, Type::Core, "change clash mode to {mode}");
match handle::Handle::mihomo()
.await
.patch_base_config(&json_value)
.await
{
Ok(_) => {
// 更新订阅
Config::clash()
.await
.edit_draft(|d| d.patch_config(mapping));
// 分离数据获取和异步调用
let clash_data = Config::clash().await.data_arc();
if clash_data.save_config().await.is_ok() {
handle::Handle::refresh_clash();
logging_error!(Type::Tray, tray::Tray::global().update_menu().await);
logging_error!(
Type::Tray,
tray::Tray::global()
.update_icon(&Config::verge().await.data_arc())
.await
);
}
let is_auto_close_connection = Config::verge()
.await
.data_arc()
.auto_close_connection
.unwrap_or(false);
if is_auto_close_connection {
after_change_clash_mode();
}
}
Err(err) => logging!(error, Type::Core, "{err}"),
}
}
/// Test connection delay to a URL
pub async fn test_delay(url: String) -> anyhow::Result<u32> {
use crate::utils::network::{NetworkManager, ProxyType};
use tokio::time::Instant;
let tun_mode = Config::verge()
.await
.latest_arc()
.enable_tun_mode
.unwrap_or(false);
// 如果是TUN模式不使用代理否则使用自身代理
let proxy_type = if !tun_mode {
ProxyType::Localhost
} else {
ProxyType::None
};
let user_agent = Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0".into());
let start = Instant::now();
let response = NetworkManager::new()
.get_with_interrupt(&url, proxy_type, Some(10), user_agent, false)
.await;
match response {
Ok(response) => {
logging!(trace, Type::Network, "test_delay response: {response:#?}");
if response.status().is_success() {
Ok(start.elapsed().as_millis() as u32)
} else {
Ok(10000u32)
}
}
Err(err) => {
logging!(trace, Type::Network, "test_delay error: {err:#?}");
Err(err)
}
}
}