feat: integrate tauri-plugin-clipboard-manager and add system info commands (#5593)

This commit is contained in:
Tunglies
2025-11-25 16:58:25 +08:00
committed by GitHub
parent d3dc40e788
commit ecc272aa20
12 changed files with 82 additions and 72 deletions

1
Cargo.lock generated
View File

@@ -7578,6 +7578,7 @@ dependencies = [
"parking_lot",
"sysinfo",
"tauri",
"tauri-plugin-clipboard-manager",
]
[[package]]

View File

@@ -50,6 +50,7 @@ clash-verge-types = { path = "crates/clash-verge-types" }
tauri-plugin-clash-verge-sysinfo = { path = "crates/tauri-plugin-clash-verge-sysinfo" }
tauri = { version = "2.9.3" }
tauri-plugin-clipboard-manager = "2.3.2"
parking_lot = { version = "0.12.5", features = ["hardware-lock-elision"] }
anyhow = "1.0.100"
criterion = { version = "0.7.0", features = ["async_tokio"] }

View File

@@ -6,6 +6,7 @@ rust-version.workspace = true
[dependencies]
tauri = { workspace = true }
tauri-plugin-clipboard-manager = { workspace = true }
parking_lot = { workspace = true }
sysinfo = { version = "0.37.2", features = ["network", "system"] }

View File

@@ -0,0 +1,39 @@
use parking_lot::RwLock;
use tauri::{AppHandle, Runtime, State, command};
use tauri_plugin_clipboard_manager::{ClipboardExt as _, Error};
use crate::Platform;
// TODO 迁移,让新的结构体允许通过 tauri command 正确使用 structure.field 方式获取信息
#[command]
pub fn get_system_info(state: State<'_, RwLock<Platform>>) -> Result<String, Error> {
Ok(state.inner().read().to_string())
}
/// 获取应用的运行时间(毫秒)
#[command]
pub fn get_app_uptime(state: State<'_, RwLock<Platform>>) -> Result<u128, Error> {
Ok(state
.inner()
.read()
.appinfo
.app_startup_time
.elapsed()
.as_millis())
}
/// 检查应用是否以管理员身份运行
#[command]
pub fn app_is_admin(state: State<'_, RwLock<Platform>>) -> Result<bool, Error> {
Ok(state.inner().read().appinfo.app_is_admin)
}
#[command]
pub fn export_diagnostic_info<R: Runtime>(
app_handle: AppHandle<R>,
state: State<'_, RwLock<Platform>>,
) -> Result<(), Error> {
let info = state.inner().read().to_string();
let clipboard = app_handle.clipboard();
clipboard.write_text(info)
}

View File

@@ -3,6 +3,8 @@ use std::{
time::Instant,
};
pub mod commands;
#[cfg(windows)]
use deelevate::{PrivilegeLevel, Token};
use parking_lot::RwLock;
@@ -130,11 +132,24 @@ pub fn set_app_core_mode<R: Runtime>(app: &tauri::AppHandle<R>, mode: impl Into<
spec.appinfo.app_core_mode = mode.into();
}
#[inline]
pub fn is_current_app_handle_admin<R: Runtime>(app: &tauri::AppHandle<R>) -> bool {
let platform_spec = app.state::<RwLock<Platform>>();
let spec = platform_spec.read();
spec.appinfo.app_is_admin
}
#[inline]
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("clash_verge_sysinfo")
Builder::<R>::new("clash_verge_sysinfo")
// TODO 现在 crate 还不是真正的 tauri 插件,必须由主 lib 自行注册
// TODO 从 clash-verge 中迁移获取系统信息的 commnand 并实现优雅 structure.field 访问
// .invoke_handler(tauri::generate_handler![greet])
// .invoke_handler(tauri::generate_handler![
// commands::get_system_info,
// commands::get_app_uptime,
// commands::app_is_admin,
// commands::export_diagnostic_info,
// ])
.setup(move |app, _api| {
let app_version = app.package_info().version.to_string();
let is_admin = is_binary_admin();

View File

@@ -35,6 +35,7 @@ clash-verge-logging = { workspace = true }
clash-verge-signal = { workspace = true }
clash-verge-types = { workspace = true }
tauri-plugin-clash-verge-sysinfo = { workspace = true }
tauri-plugin-clipboard-manager = { workspace = true }
tauri = { workspace = true, features = [
"protocol-asset",
"devtools",
@@ -72,7 +73,6 @@ tauri-plugin-shell = "2.3.3"
tauri-plugin-dialog = "2.4.2"
tauri-plugin-fs = "2.4.4"
tauri-plugin-process = "2.3.1"
tauri-plugin-clipboard-manager = "2.3.2"
tauri-plugin-deep-link = "2.4.5"
tauri-plugin-window-state = "2.4.1"
zip = "6.0.0"

View File

@@ -1,59 +1,9 @@
use std::sync::Arc;
use super::CmdResult;
use crate::core::{CoreManager, handle, manager::RunningMode};
use clash_verge_logging::{Type, logging};
use parking_lot::RwLock;
use tauri::Manager as _;
use tauri_plugin_clash_verge_sysinfo::Platform;
use tauri_plugin_clipboard_manager::ClipboardExt as _;
#[tauri::command]
pub async fn export_diagnostic_info() -> CmdResult<()> {
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();
if cliboard.write_text(info).is_err() {
logging!(error, Type::System, "Failed to write to clipboard");
}
Ok(())
}
// TODO 迁移,让新的结构体允许通过 tauri command 正确使用 structure.field 方式获取信息
#[tauri::command]
pub async fn get_system_info() -> CmdResult<String> {
let app_handle = handle::Handle::app_handle();
let info = app_handle.state::<RwLock<Platform>>().read().to_string();
Ok(info)
}
use crate::core::{CoreManager, manager::RunningMode};
/// 获取当前内核运行模式
#[tauri::command]
pub async fn get_running_mode() -> Result<Arc<RunningMode>, String> {
Ok(CoreManager::global().get_running_mode())
}
/// 获取应用的运行时间(毫秒)
#[tauri::command]
pub fn get_app_uptime() -> u128 {
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 {
let app_handle = handle::Handle::app_handle();
app_handle
.state::<RwLock<Platform>>()
.read()
.appinfo
.app_is_admin
}

View File

@@ -1,9 +1,13 @@
use super::{IClashTemp, IProfiles, IVerge};
use crate::{
cmd,
config::{PrfItem, profiles_append_item_safe},
constants::{files, timing},
core::{CoreManager, handle, service, tray, validate::CoreConfigValidator},
core::{
CoreManager,
handle::{self, Handle},
service, tray,
validate::CoreConfigValidator,
},
enhance,
utils::{dirs, help},
};
@@ -14,6 +18,7 @@ use clash_verge_logging::{Type, logging, logging_error};
use clash_verge_types::runtime::IRuntime;
use smartstring::alias::String;
use std::path::PathBuf;
use tauri_plugin_clash_verge_sysinfo::is_current_app_handle_admin;
use tokio::sync::OnceCell;
use tokio::time::sleep;
@@ -60,7 +65,10 @@ impl Config {
Self::ensure_default_profile_items().await?;
// init Tun mode
if !cmd::system::is_admin() && service::is_service_available().await.is_err() {
let handle = Handle::app_handle();
let is_admin = is_current_app_handle_admin(handle);
let is_service_available = service::is_service_available().await.is_ok();
if !is_admin && !is_service_available {
let verge = Self::verge().await;
verge.edit_draft(|d| {
d.enable_tun_mode = Some(false);

View File

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

View File

@@ -1,5 +1,6 @@
use once_cell::sync::OnceCell;
use tauri::tray::TrayIconBuilder;
use tauri_plugin_clash_verge_sysinfo::is_current_app_handle_admin;
use tauri_plugin_mihomo::models::Proxies;
use tokio::fs;
#[cfg(target_os = "macos")]
@@ -303,8 +304,8 @@ impl Tray {
let verge = Config::verge().await.latest_arc();
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
let tun_mode_available =
cmd::system::is_admin() || service::is_service_available().await.is_ok();
let tun_mode_available = is_current_app_handle_admin(app_handle)
|| service::is_service_available().await.is_ok();
let mode = {
Config::clash()
.await

View File

@@ -137,6 +137,10 @@ mod app_init {
pub fn generate_handlers()
-> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static {
tauri::generate_handler![
tauri_plugin_clash_verge_sysinfo::commands::get_system_info,
tauri_plugin_clash_verge_sysinfo::commands::get_app_uptime,
tauri_plugin_clash_verge_sysinfo::commands::app_is_admin,
tauri_plugin_clash_verge_sysinfo::commands::export_diagnostic_info,
cmd::get_sys_proxy,
cmd::get_auto_proxy,
cmd::open_app_dir,
@@ -155,9 +159,7 @@ mod app_init {
cmd::notify_ui_ready,
cmd::update_ui_stage,
cmd::get_running_mode,
cmd::get_app_uptime,
cmd::get_auto_launch_status,
cmd::is_admin,
cmd::entry_lightweight_mode,
cmd::exit_lightweight_mode,
cmd::install_service,
@@ -218,8 +220,6 @@ mod app_init {
cmd::list_webdav_backup,
cmd::delete_webdav_backup,
cmd::restore_webdav_backup,
cmd::export_diagnostic_info,
cmd::get_system_info,
cmd::get_unlock_items,
cmd::check_media_unlock,
]

View File

@@ -540,7 +540,7 @@ export const exit_lightweight_mode = async () => {
export const isAdmin = async () => {
try {
return await invoke<boolean>("is_admin");
return await invoke<boolean>("app_is_admin");
} catch (error) {
console.error("检查管理员权限失败:", error);
return false;