feat(sysinfo): add tauri-plugin-clash-verge-sysinfo for system information retrieval (#5510)

* feat(sysinfo): add tauri-plugin-clash-verge-sysinfo for system information retrieval

* feat(sysinfo): add tauri-plugin-clash-verge-sysinfo for system information retrieval

* fix(service): import Manager trait for app handle in linux_running_as_root function
This commit is contained in:
Tunglies
2025-11-18 15:48:48 +08:00
committed by GitHub
parent ca35994ccb
commit 8339fabb17
13 changed files with 242 additions and 111 deletions

View File

@@ -4,6 +4,7 @@ use clash_verge_logging::{Type, logging};
use gethostname::gethostname;
use network_interface::NetworkInterface;
use serde_yaml_ng::Mapping;
use tauri_plugin_clash_verge_sysinfo;
/// get the system proxy
#[tauri::command]
@@ -68,13 +69,7 @@ pub fn get_system_hostname() -> String {
/// 获取网络接口列表
#[tauri::command]
pub fn get_network_interfaces() -> Vec<String> {
use sysinfo::Networks;
let mut result = Vec::new();
let networks = Networks::new_with_refreshed_list();
for (interface_name, _) in &networks {
result.push(interface_name.clone());
}
result
tauri_plugin_clash_verge_sysinfo::list_network_interfaces()
}
/// 获取网络接口详细信息

View File

@@ -1,33 +1,17 @@
use std::sync::Arc;
use super::CmdResult;
use crate::{
core::{CoreManager, handle, manager::RunningMode},
module::sysinfo::PlatformSpecification,
};
use crate::core::{CoreManager, handle, manager::RunningMode};
use clash_verge_logging::{Type, logging};
#[cfg(target_os = "windows")]
use deelevate::{PrivilegeLevel, Token};
use once_cell::sync::Lazy;
use parking_lot::RwLock;
use tauri::Manager;
use tauri_plugin_clash_verge_sysinfo::Platform;
use tauri_plugin_clipboard_manager::ClipboardExt as _;
use tokio::time::Instant;
// 存储应用启动时间的全局变量
static APP_START_TIME: Lazy<Instant> = Lazy::new(Instant::now);
#[cfg(not(target_os = "windows"))]
static APPS_RUN_AS_ADMIN: Lazy<bool> = Lazy::new(|| unsafe { libc::geteuid() } == 0);
#[cfg(target_os = "windows")]
static APPS_RUN_AS_ADMIN: Lazy<bool> = Lazy::new(|| {
Token::with_current_process()
.and_then(|token| token.privilege_level())
.map(|level| level != PrivilegeLevel::NotPrivileged)
.unwrap_or(false)
});
#[tauri::command]
pub async fn export_diagnostic_info() -> CmdResult<()> {
let sysinfo = PlatformSpecification::new_sync();
let info = format!("{sysinfo:?}");
let app_handle = handle::Handle::app_handle();
let info = app_handle.state::<RwLock<Platform>>().read().to_string();
let app_handle = handle::Handle::app_handle();
let cliboard = app_handle.clipboard();
@@ -37,10 +21,11 @@ pub async fn export_diagnostic_info() -> CmdResult<()> {
Ok(())
}
// TODO 迁移,让新的结构体允许通过 tauri command 正确使用 structure.field 方式获取信息
#[tauri::command]
pub async fn get_system_info() -> CmdResult<String> {
let sysinfo = PlatformSpecification::new_sync();
let info = format!("{sysinfo:?}");
let app_handle = handle::Handle::app_handle();
let info = app_handle.state::<RwLock<Platform>>().read().to_string();
Ok(info)
}
@@ -53,11 +38,22 @@ pub async fn get_running_mode() -> Result<Arc<RunningMode>, String> {
/// 获取应用的运行时间(毫秒)
#[tauri::command]
pub fn get_app_uptime() -> u128 {
APP_START_TIME.elapsed().as_millis()
let app_handle = handle::Handle::app_handle();
let startup_time = app_handle
.state::<RwLock<Platform>>()
.read()
.appinfo
.app_startup_time;
startup_time.elapsed().as_millis()
}
/// 检查应用是否以管理员身份运行
#[tauri::command]
pub fn is_admin() -> bool {
*APPS_RUN_AS_ADMIN
let app_handle = handle::Handle::app_handle();
app_handle
.state::<RwLock<Platform>>()
.read()
.appinfo
.app_is_admin
}

View File

@@ -1,17 +1,23 @@
use super::{CoreManager, RunningMode};
use crate::cmd::StringifyErr as _;
use crate::config::{Config, IVerge};
use crate::core::handle::Handle;
use crate::core::{
logger::CLASH_LOGGER,
service::{SERVICE_MANAGER, ServiceStatus},
};
use anyhow::Result;
use clash_verge_logging::{Type, logging};
use scopeguard::defer;
use smartstring::alias::String;
use tauri_plugin_clash_verge_sysinfo;
impl CoreManager {
pub async fn start_core(&self) -> Result<()> {
self.prepare_startup().await?;
defer! {
self.after_core_process();
}
match *self.get_running_mode() {
RunningMode::Service => self.start_core_by_service().await,
@@ -21,6 +27,9 @@ impl CoreManager {
pub async fn stop_core(&self) -> Result<()> {
CLASH_LOGGER.clear_logs().await;
defer! {
self.after_core_process();
}
match *self.get_running_mode() {
RunningMode::Service => self.stop_core_by_service().await,
@@ -74,6 +83,14 @@ impl CoreManager {
Ok(())
}
fn after_core_process(&self) {
let app_handle = Handle::app_handle();
tauri_plugin_clash_verge_sysinfo::set_app_core_mode(
app_handle,
self.get_running_mode().to_string(),
);
}
#[cfg(target_os = "windows")]
async fn wait_for_service_if_needed(&self) {
use crate::{config::Config, constants::timing};

View File

@@ -254,9 +254,16 @@ async fn reinstall_service() -> Result<()> {
#[cfg(target_os = "linux")]
fn linux_running_as_root() -> bool {
const ROOT_UID: u32 = 0;
unsafe { libc::geteuid() == ROOT_UID }
use crate::core::handle;
use parking_lot::RwLock;
use tauri::Manager as _;
use tauri_plugin_clash_verge_sysinfo::Platform;
let app_handle = handle::Handle::app_handle();
app_handle
.state::<RwLock<Platform>>()
.read()
.appinfo
.app_is_admin
}
#[cfg(target_os = "macos")]

View File

@@ -57,6 +57,7 @@ mod app_init {
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_clash_verge_sysinfo::init())
.plugin(
tauri_plugin_mihomo::Builder::new()
.protocol(tauri_plugin_mihomo::models::Protocol::LocalSocket)

View File

@@ -1,3 +1,2 @@
pub mod auto_backup;
pub mod lightweight;
pub mod sysinfo;

View File

@@ -1,69 +0,0 @@
use crate::{
cmd::system,
core::{CoreManager, handle},
};
use std::fmt::{self, Debug, Formatter};
use sysinfo::System;
pub struct PlatformSpecification {
system_name: String,
system_version: String,
system_kernel_version: String,
system_arch: String,
verge_version: String,
running_mode: String,
is_admin: bool,
}
impl Debug for PlatformSpecification {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
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
)
}
}
impl PlatformSpecification {
pub fn new() -> Self {
let system_name = System::name().unwrap_or_else(|| "Null".into());
let system_version = System::long_os_version().unwrap_or_else(|| "Null".into());
let system_kernel_version = System::kernel_version().unwrap_or_else(|| "Null".into());
let system_arch = System::cpu_arch();
let handler = handle::Handle::app_handle();
let verge_version = handler.package_info().version.to_string();
// 使用默认值避免在同步上下文中执行异步操作
let running_mode = "NotRunning".to_string();
let is_admin = system::is_admin();
Self {
system_name,
system_version,
system_kernel_version,
system_arch,
verge_version,
running_mode,
is_admin,
}
}
// 异步方法来获取完整的系统信息
pub fn new_sync() -> Self {
let mut info = Self::new();
let running_mode = CoreManager::global().get_running_mode();
info.running_mode = running_mode.to_string();
info
}
}