Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ use tauri::Manager;
use tauri_plugin_log::{RotationStrategy, Target, TargetKind, TimezoneStrategy};
use ws_broadcast::WsBroadcast;

#[cfg(target_os = "windows")]
fn clear_webview_boot_marker() {
let Some(exe_dir) = std::env::current_exe()
.ok()
.and_then(|path| path.parent().map(|dir| dir.to_path_buf()))
else {
return;
};
let marker = exe_dir.join("cache").join("webview_boot_pending");
let _ = std::fs::remove_file(marker);
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
// 日志目录:exe 目录/debug/logs(与前端日志同目录)
Expand Down Expand Up @@ -56,6 +68,9 @@ pub fn run() {
.build(),
)
.setup(|app| {
#[cfg(target_os = "windows")]
clear_webview_boot_marker();

// 创建 MaaState 并注册为 Tauri 管理状态
let maa_state = Arc::new(MaaState::default());

Expand Down
141 changes: 123 additions & 18 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,128 @@
#[cfg(target_os = "windows")]
mod webview2;

#[cfg(target_os = "windows")]
fn exe_dir() -> Option<std::path::PathBuf> {
std::env::current_exe()
.ok()
.and_then(|path| path.parent().map(|dir| dir.to_path_buf()))
}

#[cfg(target_os = "windows")]
fn bootstrap_log(message: &str) {
use std::io::Write;

let Some(exe_dir) = exe_dir() else {
return;
};
let debug_dir = exe_dir.join("debug");
let _ = std::fs::create_dir_all(&debug_dir);
let log_path = debug_dir.join("bootstrap.log");
if let Ok(mut file) = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(log_path)
{
let _ = writeln!(file, "{}", message);
}
}

#[cfg(target_os = "windows")]
fn webview_boot_marker_path() -> Option<std::path::PathBuf> {
exe_dir().map(|dir| dir.join("cache").join("webview_boot_pending"))
}

#[cfg(target_os = "windows")]
fn mark_webview_boot_pending() {
let Some(marker) = webview_boot_marker_path() else {
return;
};
if let Some(parent) = marker.parent() {
let _ = std::fs::create_dir_all(parent);
}
let _ = std::fs::write(marker, b"pending");
}

#[cfg(target_os = "windows")]
fn repair_webview_data_after_previous_failure() {
let Some(marker) = webview_boot_marker_path() else {
return;
};
if !marker.exists() {
return;
}

bootstrap_log("previous WebView boot did not reach Tauri setup; rotating webview_data");
let _ = std::fs::remove_file(&marker);

let Some(exe_dir) = exe_dir() else {
return;
};
let webview_data_dir = exe_dir.join("cache").join("webview_data");
if !webview_data_dir.exists() {
return;
}

let backup_name = format!(
"webview_data.bak-{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
);
let backup_dir = exe_dir.join("cache").join(backup_name);
match std::fs::rename(&webview_data_dir, &backup_dir) {
Ok(()) => bootstrap_log("rotated webview_data successfully"),
Err(e) => bootstrap_log(&format!("failed to rotate webview_data: {}", e)),
}
}

#[cfg(target_os = "windows")]
fn is_fixed_webview2_runtime_usable(runtime_dir: &std::path::Path) -> bool {
runtime_dir.is_dir()
&& runtime_dir.join("msedgewebview2.exe").is_file()
&& runtime_dir.join("EBWebView").is_dir()
}

fn main() {
#[cfg(target_os = "windows")]
bootstrap_log("mxu bootstrap start");

if mxu_lib::commands::system::has_help_flag() {
#[cfg(target_os = "windows")]
bootstrap_log("help flag detected; exiting");
mxu_lib::commands::system::print_cli_help_text();
std::process::exit(0);
}

#[cfg(target_os = "windows")]
{
repair_webview_data_after_previous_failure();

// 设置 WebView2 数据目录为程序所在目录下的 webview_data 文件夹
// 这样可以避免用户名包含特殊字符(如中文)导致 WebView2 无法创建数据目录的问题
if let Ok(exe_path) = std::env::current_exe() {
if let Some(exe_dir) = exe_path.parent() {
let webview_data_dir = exe_dir.join("cache").join("webview_data");
// 确保目录存在
let _ = std::fs::create_dir_all(&webview_data_dir);
std::env::set_var("WEBVIEW2_USER_DATA_FOLDER", &webview_data_dir);

// 检测已缓存的 WebView2 固定版本运行时
// 验证目录包含关键文件以确保运行时完整可用
if let Ok(webview2_runtime_dir) = webview2::get_webview2_runtime_dir() {
if webview2_runtime_dir.is_dir()
&& webview2_runtime_dir.join("msedgewebview2.exe").exists()
{
std::env::set_var(
"WEBVIEW2_BROWSER_EXECUTABLE_FOLDER",
&webview2_runtime_dir,
);
}
if let Some(exe_dir) = exe_dir() {
let webview_data_dir = exe_dir.join("cache").join("webview_data");
// 确保目录存在
match std::fs::create_dir_all(&webview_data_dir) {
Ok(()) => bootstrap_log("webview_data directory ready"),
Err(e) => bootstrap_log(&format!("failed to create webview_data: {}", e)),
}
std::env::set_var("WEBVIEW2_USER_DATA_FOLDER", &webview_data_dir);

// 检测已缓存的 WebView2 固定版本运行时
// 验证目录包含关键文件以确保运行时完整可用,否则回退到系统 WebView2/重新下载
if let Ok(webview2_runtime_dir) = webview2::get_webview2_runtime_dir() {
if is_fixed_webview2_runtime_usable(&webview2_runtime_dir) {
std::env::set_var(
"WEBVIEW2_BROWSER_EXECUTABLE_FOLDER",
&webview2_runtime_dir,
);
bootstrap_log("using fixed WebView2 runtime");
} else if webview2_runtime_dir.exists() {
bootstrap_log(
"fixed WebView2 runtime is incomplete; falling back to system/runtime install",
);
}
}
}
Expand All @@ -40,6 +134,7 @@ fn main() {
if std::env::var_os("WEBVIEW2_BROWSER_EXECUTABLE_FOLDER").is_none()
&& !webview2::ensure_webview2()
{
bootstrap_log("WebView2 is unavailable; exiting before Tauri run");
std::process::exit(1);
}

Expand All @@ -51,6 +146,8 @@ fn main() {
Ok(p) => p,
Err(_) => {
// 获取路径失败就按普通权限继续
bootstrap_log("failed to get current exe before elevation; entering run");
mark_webview_boot_pending();
mxu_lib::run();
return;
}
Expand All @@ -69,10 +166,18 @@ fn main() {

if result.is_ok() {
// 新的管理员进程已启动,退出当前普通权限进程
bootstrap_log("elevated process started; exiting non-elevated bootstrap");
std::process::exit(0);
}
bootstrap_log("elevation failed or was cancelled; continuing normally");
}
}

#[cfg(target_os = "windows")]
{
bootstrap_log("entering mxu_lib::run");
mark_webview_boot_pending();
}

mxu_lib::run()
}
Loading