75 lines
2.2 KiB
Rust
75 lines
2.2 KiB
Rust
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
const PORTABLE_DIR_NAME: &str = ".Axolotl";
|
|
|
|
static PORTABLE_MODE: AtomicBool = AtomicBool::new(false);
|
|
|
|
/// 在启动时初始化便携模式
|
|
/// 检查 `.Axolotl` 文件夹是否存在且可写
|
|
/// 如果存在且可写,将 `THESEUS_CONFIG_DIR` 环境变量设置为该路径
|
|
/// 返回 `true` 如果便携模式已启用,否则返回 `false`
|
|
///
|
|
/// 必须在 main() 开头、任何其他线程(包括 tokio runtime)启动之前调用。
|
|
/// 此函数内部会调用 `std::env::set_var`,该函数在 Rust 中不是线程安全的。
|
|
pub unsafe fn init_portable_mode() -> bool {
|
|
let exe_path = match std::env::current_exe() {
|
|
Ok(p) => p,
|
|
Err(_) => return false,
|
|
};
|
|
|
|
let Some(app_dir) = exe_path.parent() else {
|
|
return false;
|
|
};
|
|
|
|
let portable_dir = app_dir.join(PORTABLE_DIR_NAME);
|
|
|
|
if !portable_dir.is_dir() {
|
|
return false;
|
|
}
|
|
if !try_write_test(&portable_dir) {
|
|
return false;
|
|
}
|
|
|
|
// SAFETY: 调用者保证此时没有其他线程访问环境变量
|
|
unsafe {
|
|
std::env::set_var("THESEUS_CONFIG_DIR", &portable_dir);
|
|
}
|
|
PORTABLE_MODE.store(true, Ordering::Relaxed);
|
|
|
|
tracing::info!(
|
|
"Portable mode enabled: THESEUS_CONFIG_DIR={}",
|
|
portable_dir.display()
|
|
);
|
|
|
|
true
|
|
}
|
|
|
|
/// 尝试在目标目录中创建并删除临时文件以验证可写性。
|
|
/// 先删除可能残留的 `.write_test`,避免已有的只读文件导致 `File::create` 失败。
|
|
fn try_write_test(dir: &std::path::Path) -> bool {
|
|
let test_file = dir.join(".write_test");
|
|
|
|
let _ = std::fs::remove_file(&test_file);
|
|
|
|
match std::fs::File::create(&test_file) {
|
|
Ok(_) => {
|
|
let _ = std::fs::remove_file(&test_file);
|
|
true
|
|
}
|
|
Err(e) => {
|
|
tracing::warn!(
|
|
"Portable directory {} exists but is not writable: {}",
|
|
dir.display(),
|
|
e
|
|
);
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Tauri 命令:检查应用程序是否运行在便携模式下
|
|
#[tauri::command]
|
|
pub fn is_portable_mode() -> bool {
|
|
PORTABLE_MODE.load(Ordering::Relaxed)
|
|
}
|