This repository has been archived on 2026-04-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
win-cleaner/src-tauri/src/backend/fast_clean.rs
Julian Freeman fd2566ca26 refactor backend
2026-04-17 11:09:49 -04:00

162 lines
4.8 KiB
Rust

use std::fs;
use std::path::Path;
use std::time::{Duration, SystemTime};
use crate::backend::models::{CleanResult, CleaningConfig, FastScanResult, ScanItem};
use crate::backend::utils::format_size;
fn get_fast_cleaning_configs() -> Vec<CleaningConfig> {
let mut configs = Vec::new();
if let Ok(temp) = std::env::var("TEMP") {
configs.push(CleaningConfig::new("用户临时文件", &temp, None, true));
}
configs.push(CleaningConfig::new("系统临时文件", "C:\\Windows\\Temp", None, true));
configs.push(CleaningConfig::new(
"Windows 更新残留",
"C:\\Windows\\SoftwareDistribution\\Download",
Some(10),
true,
));
configs.push(CleaningConfig::new(
"内核转储文件",
"C:\\Windows\\LiveKernelReports",
None,
false,
));
configs
}
pub async fn run_fast_scan() -> FastScanResult {
let configs = get_fast_cleaning_configs();
let mut items = Vec::new();
let mut total_bytes = 0;
let mut total_count = 0;
for config in configs {
let (size, count) = get_dir_stats(Path::new(&config.path), config.filter_days);
items.push(ScanItem {
name: config.name,
path: config.path,
size,
count,
enabled: config.default_enabled,
});
total_bytes += size;
total_count += count;
}
FastScanResult {
items,
total_size: format_size(total_bytes),
total_count,
}
}
fn get_dir_stats(path: &Path, filter_days: Option<u64>) -> (u64, u32) {
if !path.exists() {
return (0, 0);
}
let mut size = 0;
let mut count = 0;
let now = SystemTime::now();
let dur = filter_days.map(|days| Duration::from_secs(days * 24 * 3600));
for entry in walkdir::WalkDir::new(path).into_iter().filter_map(|e| e.ok()) {
if entry.file_type().is_file() {
let mut allowed = true;
if let (Some(filter_duration), Ok(metadata)) = (dur, entry.metadata()) {
if let Ok(modified_time) = metadata.modified() {
if let Ok(elapsed) = now.duration_since(modified_time) {
if elapsed < filter_duration {
allowed = false;
}
}
}
}
if allowed {
size += entry.metadata().map(|m| m.len()).unwrap_or(0);
count += 1;
}
}
}
(size, count)
}
pub async fn run_fast_clean(selected_paths: Vec<String>) -> Result<CleanResult, String> {
let configs = get_fast_cleaning_configs();
let mut success_count = 0;
let mut fail_count = 0;
let mut total_freed = 0;
for config in configs {
if selected_paths.contains(&config.path) {
let path = Path::new(&config.path);
if path.exists() {
let (freed, success, fail) = clean_directory_contents(path, config.filter_days);
total_freed += freed;
success_count += success;
fail_count += fail;
}
}
}
Ok(CleanResult {
total_freed: format_size(total_freed),
success_count,
fail_count,
})
}
pub fn clean_directory_contents(path: &Path, filter_days: Option<u64>) -> (u64, u32, u32) {
let mut freed = 0;
let mut success = 0;
let mut fail = 0;
let now = SystemTime::now();
let dur = filter_days.map(|days| Duration::from_secs(days * 24 * 3600));
if let Ok(entries) = fs::read_dir(path) {
for entry in entries.filter_map(|e| e.ok()) {
let entry_path = entry.path();
let metadata = entry.metadata();
let size = metadata.as_ref().map(|m| m.len()).unwrap_or(0);
if let (Some(filter_duration), Ok(metadata)) = (dur, &metadata) {
if let Ok(modified_time) = metadata.modified() {
if let Ok(elapsed) = now.duration_since(modified_time) {
if elapsed < filter_duration {
continue;
}
}
}
}
if entry_path.is_file() {
if fs::remove_file(&entry_path).is_ok() {
freed += size;
success += 1;
} else {
fail += 1;
}
} else if entry_path.is_dir() {
let (dir_freed, dir_success, dir_fail) =
clean_directory_contents(&entry_path, filter_days);
freed += dir_freed;
success += dir_success;
fail += dir_fail;
if fs::remove_dir(&entry_path).is_ok() {
success += 1;
}
}
}
}
(freed, success, fail)
}