use std::collections::HashMap;
use std::fs;
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, OnceLock};
use log::{error, info};
static GLOBAL_TEMP_CLEANER: OnceLock<TempCleaner> = OnceLock::new();
pub type ExitNotifier = dyn Fn() + Send + Sync;
pub struct TempCleaner {
paths: Mutex<Vec<String>>,
notifiers: Mutex<HashMap<String, Arc<ExitNotifier>>>,
executed: AtomicBool,
}
impl TempCleaner {
pub fn object_init() {
let _ = GLOBAL_TEMP_CLEANER.set(TempCleaner {
paths: Mutex::new(Vec::new()),
notifiers: Mutex::new(HashMap::new()),
executed: AtomicBool::new(false),
});
}
pub fn add_path(path: String) {
if let Some(tmp) = GLOBAL_TEMP_CLEANER.get() {
tmp.paths.lock().unwrap().push(path);
}
}
pub fn add_exit_notifier(id: String, exit: Arc<ExitNotifier>) {
if let Some(tmp) = GLOBAL_TEMP_CLEANER.get() {
tmp.notifiers.lock().unwrap().insert(id, exit);
}
}
pub fn remove_exit_notifier(id: &str) {
if let Some(tmp) = GLOBAL_TEMP_CLEANER.get() {
tmp.notifiers.lock().unwrap().remove(id);
}
}
fn clean_files(&self) {
while let Some(path) = self.paths.lock().unwrap().pop() {
if Path::new(&path).exists() {
if let Err(ref e) = fs::remove_file(&path) {
error!("Failed to delete console / socket file:{} :{}", &path, e);
} else {
info!("Delete file: {} successfully", &path);
}
} else {
info!("file: {} has been removed", &path);
}
}
}
fn exit_notifier(&self) {
for (_id, exit) in self.notifiers.lock().unwrap().iter() {
exit();
}
}
pub fn clean() {
if let Some(tmp) = GLOBAL_TEMP_CLEANER.get() {
tmp.clean_files();
tmp.exit_notifier();
tmp.paths.lock().unwrap().clear();
tmp.notifiers.lock().unwrap().clear();
tmp.executed.store(true, Ordering::SeqCst);
}
}
pub fn is_cleaned() -> bool {
if let Some(tmp) = GLOBAL_TEMP_CLEANER.get() {
return tmp.executed.load(Ordering::SeqCst);
}
true
}
}