2025-03-01 22:52:43 +08:00
|
|
|
use super::CmdResult;
|
2025-03-27 11:12:08 +08:00
|
|
|
use crate::{
|
|
|
|
|
feat, logging,
|
2025-10-14 19:55:22 +08:00
|
|
|
utils::{
|
|
|
|
|
dirs::{self, PathBufExec},
|
|
|
|
|
logging::Type,
|
|
|
|
|
},
|
2025-03-27 11:12:08 +08:00
|
|
|
wrap_err,
|
|
|
|
|
};
|
2025-10-14 19:55:22 +08:00
|
|
|
use std::path::Path;
|
2025-08-23 00:20:58 +08:00
|
|
|
use tauri::{AppHandle, Manager};
|
2025-10-14 19:55:22 +08:00
|
|
|
use tokio::fs;
|
2025-03-01 22:52:43 +08:00
|
|
|
|
|
|
|
|
/// 打开应用程序所在目录
|
|
|
|
|
#[tauri::command]
|
2025-08-26 01:49:51 +08:00
|
|
|
pub async fn open_app_dir() -> CmdResult<()> {
|
2025-03-01 22:52:43 +08:00
|
|
|
let app_dir = wrap_err!(dirs::app_home_dir())?;
|
|
|
|
|
wrap_err!(open::that(app_dir))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 打开核心所在目录
|
|
|
|
|
#[tauri::command]
|
2025-08-26 01:49:51 +08:00
|
|
|
pub async fn open_core_dir() -> CmdResult<()> {
|
2025-03-01 22:52:43 +08:00
|
|
|
let core_dir = wrap_err!(tauri::utils::platform::current_exe())?;
|
|
|
|
|
let core_dir = core_dir.parent().ok_or("failed to get core dir")?;
|
|
|
|
|
wrap_err!(open::that(core_dir))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 打开日志目录
|
|
|
|
|
#[tauri::command]
|
2025-08-26 01:49:51 +08:00
|
|
|
pub async fn open_logs_dir() -> CmdResult<()> {
|
2025-03-01 22:52:43 +08:00
|
|
|
let log_dir = wrap_err!(dirs::app_logs_dir())?;
|
|
|
|
|
wrap_err!(open::that(log_dir))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 打开网页链接
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub fn open_web_url(url: String) -> CmdResult<()> {
|
|
|
|
|
wrap_err!(open::that(url))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 打开/关闭开发者工具
|
|
|
|
|
#[tauri::command]
|
2025-08-23 00:20:58 +08:00
|
|
|
pub fn open_devtools(app_handle: AppHandle) {
|
2025-03-01 22:52:43 +08:00
|
|
|
if let Some(window) = app_handle.get_webview_window("main") {
|
|
|
|
|
if !window.is_devtools_open() {
|
|
|
|
|
window.open_devtools();
|
|
|
|
|
} else {
|
|
|
|
|
window.close_devtools();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 退出应用
|
|
|
|
|
#[tauri::command]
|
2025-08-26 01:49:51 +08:00
|
|
|
pub async fn exit_app() {
|
|
|
|
|
feat::quit().await;
|
2025-03-01 22:52:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 重启应用
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub async fn restart_app() -> CmdResult<()> {
|
2025-08-26 01:49:51 +08:00
|
|
|
feat::restart_app().await;
|
2025-03-01 22:52:43 +08:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取便携版标识
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub fn get_portable_flag() -> CmdResult<bool> {
|
|
|
|
|
Ok(*dirs::PORTABLE_FLAG.get().unwrap_or(&false))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取应用目录
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub fn get_app_dir() -> CmdResult<String> {
|
2025-10-14 09:24:39 +08:00
|
|
|
let app_home_dir = wrap_err!(dirs::app_home_dir())?.to_string_lossy().into();
|
2025-03-01 22:52:43 +08:00
|
|
|
Ok(app_home_dir)
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-17 09:48:44 +08:00
|
|
|
/// 获取当前自启动状态
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub fn get_auto_launch_status() -> CmdResult<bool> {
|
|
|
|
|
use crate::core::sysopt::Sysopt;
|
|
|
|
|
wrap_err!(Sysopt::global().get_launch_status())
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-01 22:52:43 +08:00
|
|
|
/// 下载图标缓存
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String> {
|
|
|
|
|
let icon_cache_dir = wrap_err!(dirs::app_home_dir())?.join("icons").join("cache");
|
2025-03-08 13:31:20 +08:00
|
|
|
let icon_path = icon_cache_dir.join(&name);
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-08 13:31:20 +08:00
|
|
|
if icon_path.exists() {
|
2025-10-14 09:24:39 +08:00
|
|
|
return Ok(icon_path.to_string_lossy().into());
|
2025-03-08 13:31:20 +08:00
|
|
|
}
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-01 22:52:43 +08:00
|
|
|
if !icon_cache_dir.exists() {
|
|
|
|
|
let _ = std::fs::create_dir_all(&icon_cache_dir);
|
|
|
|
|
}
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-08 13:31:20 +08:00
|
|
|
let temp_path = icon_cache_dir.join(format!("{}.downloading", &name));
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-09 02:34:57 +08:00
|
|
|
let response = wrap_err!(reqwest::get(&url).await)?;
|
2025-03-13 12:51:20 +08:00
|
|
|
|
|
|
|
|
let content_type = response
|
|
|
|
|
.headers()
|
2025-03-09 02:34:57 +08:00
|
|
|
.get(reqwest::header::CONTENT_TYPE)
|
|
|
|
|
.and_then(|v| v.to_str().ok())
|
|
|
|
|
.unwrap_or("");
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-09 02:34:57 +08:00
|
|
|
let is_image = content_type.starts_with("image/");
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-08 13:31:20 +08:00
|
|
|
let content = wrap_err!(response.bytes().await)?;
|
2025-03-13 12:51:20 +08:00
|
|
|
|
|
|
|
|
let is_html = content.len() > 15
|
|
|
|
|
&& (content.starts_with(b"<!DOCTYPE html")
|
|
|
|
|
|| content.starts_with(b"<html")
|
|
|
|
|
|| content.starts_with(b"<?xml"));
|
|
|
|
|
|
2025-03-09 02:34:57 +08:00
|
|
|
if is_image && !is_html {
|
|
|
|
|
{
|
|
|
|
|
let mut file = match std::fs::File::create(&temp_path) {
|
|
|
|
|
Ok(file) => file,
|
|
|
|
|
Err(_) => {
|
|
|
|
|
if icon_path.exists() {
|
2025-10-14 09:24:39 +08:00
|
|
|
return Ok(icon_path.to_string_lossy().into());
|
2025-03-09 02:34:57 +08:00
|
|
|
}
|
2025-08-18 02:02:25 +08:00
|
|
|
return Err("Failed to create temporary file".into());
|
2025-03-08 13:31:20 +08:00
|
|
|
}
|
2025-03-09 02:34:57 +08:00
|
|
|
};
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-09 02:34:57 +08:00
|
|
|
wrap_err!(std::io::copy(&mut content.as_ref(), &mut file))?;
|
|
|
|
|
}
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-03-09 02:34:57 +08:00
|
|
|
if !icon_path.exists() {
|
|
|
|
|
match std::fs::rename(&temp_path, &icon_path) {
|
2025-03-13 12:51:20 +08:00
|
|
|
Ok(_) => {}
|
2025-03-09 02:34:57 +08:00
|
|
|
Err(_) => {
|
2025-10-14 19:55:22 +08:00
|
|
|
let _ = temp_path.remove_if_exists().await;
|
2025-03-09 02:34:57 +08:00
|
|
|
if icon_path.exists() {
|
2025-10-14 09:24:39 +08:00
|
|
|
return Ok(icon_path.to_string_lossy().into());
|
2025-03-09 02:34:57 +08:00
|
|
|
}
|
2025-03-08 13:31:20 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-03-09 02:34:57 +08:00
|
|
|
} else {
|
2025-10-14 19:55:22 +08:00
|
|
|
let _ = temp_path.remove_if_exists().await;
|
2025-03-08 13:31:20 +08:00
|
|
|
}
|
2025-03-13 12:51:20 +08:00
|
|
|
|
2025-10-14 09:24:39 +08:00
|
|
|
Ok(icon_path.to_string_lossy().into())
|
2025-03-08 13:31:20 +08:00
|
|
|
} else {
|
2025-10-14 19:55:22 +08:00
|
|
|
let _ = temp_path.remove_if_exists().await;
|
2025-06-27 23:30:35 +08:00
|
|
|
Err(format!("下载的内容不是有效图片: {url}"))
|
2025-03-08 13:31:20 +08:00
|
|
|
}
|
2025-03-01 22:52:43 +08:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 20:46:17 +08:00
|
|
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct IconInfo {
|
|
|
|
|
name: String,
|
|
|
|
|
previous_t: String,
|
|
|
|
|
current_t: String,
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-01 22:52:43 +08:00
|
|
|
/// 复制图标文件
|
|
|
|
|
#[tauri::command]
|
2025-10-14 19:55:22 +08:00
|
|
|
pub async fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<String> {
|
2025-03-04 20:46:17 +08:00
|
|
|
let file_path = Path::new(&path);
|
|
|
|
|
|
2025-03-01 22:52:43 +08:00
|
|
|
let icon_dir = wrap_err!(dirs::app_home_dir())?.join("icons");
|
|
|
|
|
if !icon_dir.exists() {
|
2025-10-14 19:55:22 +08:00
|
|
|
let _ = fs::create_dir_all(&icon_dir).await;
|
2025-03-01 22:52:43 +08:00
|
|
|
}
|
2025-10-14 09:24:39 +08:00
|
|
|
let ext: String = match file_path.extension() {
|
|
|
|
|
Some(e) => e.to_string_lossy().into(),
|
|
|
|
|
None => "ico".into(),
|
2025-03-01 22:52:43 +08:00
|
|
|
};
|
|
|
|
|
|
2025-03-04 20:46:17 +08:00
|
|
|
let dest_path = icon_dir.join(format!(
|
|
|
|
|
"{0}-{1}.{ext}",
|
|
|
|
|
icon_info.name, icon_info.current_t
|
|
|
|
|
));
|
2025-03-01 22:52:43 +08:00
|
|
|
if file_path.exists() {
|
2025-03-04 20:46:17 +08:00
|
|
|
if icon_info.previous_t.trim() != "" {
|
2025-10-14 19:55:22 +08:00
|
|
|
icon_dir
|
|
|
|
|
.join(format!("{0}-{1}.png", icon_info.name, icon_info.previous_t))
|
|
|
|
|
.remove_if_exists()
|
|
|
|
|
.await
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
icon_dir
|
|
|
|
|
.join(format!("{0}-{1}.ico", icon_info.name, icon_info.previous_t))
|
|
|
|
|
.remove_if_exists()
|
|
|
|
|
.await
|
|
|
|
|
.unwrap_or_default();
|
2025-03-04 20:46:17 +08:00
|
|
|
}
|
2025-03-27 11:12:08 +08:00
|
|
|
logging!(
|
|
|
|
|
info,
|
2025-03-28 03:39:21 +08:00
|
|
|
Type::Cmd,
|
2025-03-27 11:12:08 +08:00
|
|
|
"Copying icon file path: {:?} -> file dist: {:?}",
|
|
|
|
|
path,
|
|
|
|
|
dest_path
|
|
|
|
|
);
|
2025-10-14 19:55:22 +08:00
|
|
|
match fs::copy(file_path, &dest_path).await {
|
2025-10-14 09:24:39 +08:00
|
|
|
Ok(_) => Ok(dest_path.to_string_lossy().into()),
|
2025-03-01 22:52:43 +08:00
|
|
|
Err(err) => Err(err.to_string()),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-10-14 09:24:39 +08:00
|
|
|
Err("file not found".into())
|
2025-03-01 22:52:43 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-16 00:10:06 +08:00
|
|
|
|
|
|
|
|
/// 通知UI已准备就绪
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub fn notify_ui_ready() -> CmdResult<()> {
|
|
|
|
|
log::info!(target: "app", "前端UI已准备就绪");
|
2025-08-29 23:51:09 +08:00
|
|
|
crate::utils::resolve::ui::mark_ui_ready();
|
2025-04-16 00:10:06 +08:00
|
|
|
Ok(())
|
|
|
|
|
}
|
2025-04-20 23:47:09 +08:00
|
|
|
|
2025-05-10 01:25:50 +08:00
|
|
|
/// UI加载阶段
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
pub fn update_ui_stage(stage: String) -> CmdResult<()> {
|
2025-06-27 23:30:35 +08:00
|
|
|
log::info!(target: "app", "UI加载阶段更新: {stage}");
|
2025-05-10 01:25:50 +08:00
|
|
|
|
2025-08-29 23:51:09 +08:00
|
|
|
use crate::utils::resolve::ui::UiReadyStage;
|
2025-05-10 01:25:50 +08:00
|
|
|
|
|
|
|
|
let stage_enum = match stage.as_str() {
|
|
|
|
|
"NotStarted" => UiReadyStage::NotStarted,
|
|
|
|
|
"Loading" => UiReadyStage::Loading,
|
|
|
|
|
"DomReady" => UiReadyStage::DomReady,
|
|
|
|
|
"ResourcesLoaded" => UiReadyStage::ResourcesLoaded,
|
|
|
|
|
"Ready" => UiReadyStage::Ready,
|
|
|
|
|
_ => {
|
2025-06-27 23:30:35 +08:00
|
|
|
log::warn!(target: "app", "未知的UI加载阶段: {stage}");
|
|
|
|
|
return Err(format!("未知的UI加载阶段: {stage}"));
|
2025-05-10 01:25:50 +08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-08-29 23:51:09 +08:00
|
|
|
crate::utils::resolve::ui::update_ui_ready_stage(stage_enum);
|
2025-05-10 01:25:50 +08:00
|
|
|
Ok(())
|
|
|
|
|
}
|