feat: 视频缓存自动清理
- 应用启动时后台清理 video_cache 目录 - 删除超过 30 天未修改的缓存文件 - 总容量超 500MB 时,按修改时间删最旧文件直到 300MB - 不阻塞首屏加载
This commit is contained in:
@@ -46,6 +46,71 @@ pub struct ApiResponse<T> {
|
||||
pub data: Option<T>,
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 视频缓存清理
|
||||
// ============================================================
|
||||
|
||||
/// 清理 video_cache 目录
|
||||
///
|
||||
/// 策略:
|
||||
/// 1. 删除超过 30 天未修改的文件
|
||||
/// 2. 总容量超过 500MB 时,按修改时间删最旧文件直到 300MB
|
||||
fn clean_video_cache(app_data_dir: &std::path::Path) {
|
||||
let cache_dir = app_data_dir.join("video_cache");
|
||||
if !cache_dir.exists() {
|
||||
return;
|
||||
}
|
||||
|
||||
let max_age = std::time::Duration::from_secs(30 * 24 * 60 * 60);
|
||||
let max_total_size: u64 = 500 * 1024 * 1024;
|
||||
let target_size: u64 = 300 * 1024 * 1024;
|
||||
let now = std::time::SystemTime::now();
|
||||
|
||||
let mut entries: Vec<(std::path::PathBuf, std::time::SystemTime, u64)> = Vec::new();
|
||||
let mut total_size: u64 = 0;
|
||||
|
||||
let read_dir = match std::fs::read_dir(&cache_dir) {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
eprintln!("[cache] 无法读取缓存目录: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for entry in read_dir.flatten() {
|
||||
let Ok(metadata) = entry.metadata() else { continue };
|
||||
if !metadata.is_file() { continue; }
|
||||
let mtime = metadata.modified().unwrap_or(now);
|
||||
let size = metadata.len();
|
||||
total_size += size;
|
||||
entries.push((entry.path(), mtime, size));
|
||||
}
|
||||
|
||||
// 1. 删除超过 30 天的文件
|
||||
let mut deleted_size: u64 = 0;
|
||||
for (path, mtime, size) in &entries {
|
||||
if now.duration_since(*mtime).unwrap_or_default() > max_age {
|
||||
if std::fs::remove_file(path).is_ok() {
|
||||
deleted_size += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 容量超限,删最旧的
|
||||
let remaining_size = total_size.saturating_sub(deleted_size);
|
||||
if remaining_size > max_total_size {
|
||||
let mut sorted = entries;
|
||||
sorted.sort_by_key(|(_, mtime, _)| *mtime);
|
||||
let mut to_free = remaining_size.saturating_sub(target_size);
|
||||
for (path, _, size) in sorted {
|
||||
if to_free == 0 { break; }
|
||||
if path.exists() && std::fs::remove_file(&path).is_ok() {
|
||||
to_free = to_free.saturating_sub(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 应用入口
|
||||
// ============================================================
|
||||
@@ -69,7 +134,9 @@ pub fn run() {
|
||||
.setup(|app| {
|
||||
// 初始化应用数据目录(所有业务数据的根目录)
|
||||
if let Ok(app_data_dir) = app.path().app_local_data_dir() {
|
||||
crate::storage::init_app_data_dir(app_data_dir);
|
||||
crate::storage::init_app_data_dir(app_data_dir.clone());
|
||||
// 后台清理过期视频缓存,不阻塞首屏
|
||||
std::thread::spawn(move || clean_video_cache(&app_data_dir));
|
||||
}
|
||||
|
||||
// 窗口初始 visible=false,setup 阶段先显示窗口
|
||||
|
||||
Reference in New Issue
Block a user