use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{LazyLock, Mutex};
use crate::domain::undo::UndoAction;
static UNDO_STACK: LazyLock<Mutex<Vec<UndoAction>>> = LazyLock::new(|| Mutex::new(Vec::new()));
pub static UNDO_RUNNING: AtomicBool = AtomicBool::new(false);
pub static INTERRUPTED: AtomicBool = AtomicBool::new(false);
pub fn init_signal_handler() {
ctrlc::set_handler(move || {
INTERRUPTED.store(true, Ordering::SeqCst);
})
.expect("设置 Ctrl+C 处理器失败");
}
pub fn register_undo(action: UndoAction) {
if let Ok(mut stack) = UNDO_STACK.lock() {
stack.push(action);
}
}
pub fn undo_all() {
if UNDO_RUNNING.swap(true, Ordering::SeqCst) {
return; }
let actions = UNDO_STACK
.lock()
.map(|mut stack| std::mem::take(&mut *stack))
.ok();
if let Some(mut actions) = actions {
actions.reverse();
for action in actions {
eprintln!(" ⮐ 回退: {}", action.description);
action.execute();
}
}
UNDO_RUNNING.store(false, Ordering::SeqCst);
}
#[allow(dead_code)]
pub fn undo_depth() -> usize {
UNDO_STACK.lock().map(|s| s.len()).unwrap_or(0)
}
pub fn register_file_backup(description: String, backup_path: String, original_path: String) {
register_undo(UndoAction::new(
description,
Box::new(move || {
let _ = std::fs::copy(&backup_path, &original_path);
let _ = std::fs::remove_file(&backup_path);
}),
));
}
pub fn register_package_remove(description: String, package: String) {
register_undo(UndoAction::new(
description,
Box::new(move || {
for pm in &["apt", "yum", "dnf"] {
let _ = std::process::Command::new(pm)
.args(["remove", "-y", &package])
.output();
}
}),
));
}
pub fn register_user_remove(username: String) {
register_undo(UndoAction::new(
format!("删除用户 '{username}'"),
Box::new(move || {
let _ = std::process::Command::new("userdel")
.args(["-r", &username])
.output();
}),
));
}
pub fn register_command_undo(description: String, cmd: Vec<String>) {
register_undo(UndoAction::new(
description,
Box::new(move || {
if cmd.len() > 1 {
let _ = std::process::Command::new(&cmd[0]).args(&cmd[1..]).output();
}
}),
));
}