Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ 支持计算缓存目录大小和清理超期缓存 #82

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions src-tauri/src/commands/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
use crate::state::get_cache_dir;
use once_cell::sync::Lazy;
use std::sync::Mutex;
use std::time::{Duration, SystemTime};
use std::{fmt, fs, io};
use tauri::{command, AppHandle};
use tracing::{debug, trace, info};

static CACHE_CLEAR_MUTEX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(tag = "status", content = "data")]
pub enum ClearStatus {
Clearing,
Done(u64),
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
}

impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serializer.serialize_str(self.to_string().as_ref())
}
}

#[derive(Debug)]
enum FileSize {
B(u64),
KB(f64),
MB(f64),
GB(f64),
TB(f64),
}

impl FileSize {
pub fn new(bytes_size: u64) -> Self {
let level: [u64; 5] = {
let mut arr = [0; 5];
for (i, item) in arr.iter_mut().enumerate() {
*item = bytes_size >> (i * 10);
}
arr.reverse();
arr
};

fn round_size(main: u64, sub: u64) -> f64 {
(main as f64) + (sub & 1023) as f64 / 1024.0
}

debug!("level: {:?}", level);
match level {
[0, 0, 0, 0, b] => FileSize::B(b),
[0, 0, 0, kb, b] => FileSize::KB(round_size(kb, b)),
[0, 0, mb, kb, _] => FileSize::MB(round_size(mb, kb)),
[0, gb, mb, _, _] => FileSize::GB(round_size(gb, mb)),
[tb, gb, _, _, _] => FileSize::TB(round_size(tb, gb)),
}
}
}

impl fmt::Display for FileSize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FileSize::B(b) => write!(f, "{} B", b),
FileSize::KB(kb) => write!(f, "{:.1} KB", kb),
FileSize::MB(mb) => write!(f, "{:.1} MB", mb),
FileSize::GB(gb) => write!(f, "{:.1} GB", gb),
FileSize::TB(tb) => write!(f, "{:.1} TB", tb),
}
}
}

#[command(async)]
pub async fn get_cache_dir_size(app: AppHandle) -> Result<String, Error> {
fn calc_dir_size(mut dir: fs::ReadDir) -> io::Result<u64> {
dir.try_fold(0, |acc, file| {
let file = file?;
let size = match file.metadata()? {
data if data.is_dir() => calc_dir_size(fs::read_dir(file.path())?)?,
data => data.len(),
};
trace!("calc current file size: {}", size);
Ok(acc + size)
})
}

let bytes_size = calc_dir_size(fs::read_dir(get_cache_dir(app))?)?;
info!("cache dir size: {}", bytes_size);

Ok(FileSize::new(bytes_size).to_string())
}

#[command(async)]
pub async fn clear_cache_dir(app: AppHandle) -> Result<ClearStatus, Error> {
let lock = CACHE_CLEAR_MUTEX.try_lock();
if lock.is_err() {
return Ok(ClearStatus::Clearing);
}

let cache_dir = get_cache_dir(app);
// 删除3天前的缓存
let now = SystemTime::now();
let mut count = 0;

for entry in fs::read_dir(cache_dir)? {
let entry = entry?;
let metadata = entry.metadata()?;
let modified = metadata.modified().unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里应该使用的是AccessTime 吧?将近3个月没有访问的文件夹删除?


if now.duration_since(modified).unwrap() > Duration::from_secs(60 * 60 * 24 * 3) {
debug!("remove dir: {:?}", entry.path());
fs::remove_dir_all(entry.path())?;
count += 1;
}
}
Comment on lines +112 to +122
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里只遍历一层会不会容易删除不完整?增加一层便利深度也许更好?


debug!("clear cache dir done, remove {} dirs", count);
Ok(ClearStatus::Done(count))
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_file_size() {
assert_eq!(FileSize::new(0).to_string(), "0 B");
assert_eq!(FileSize::new(1023).to_string(), "1023 B");
assert_eq!(FileSize::new(1024).to_string(), "1.0 KB");
assert_eq!(FileSize::new(1024 * 1024 - 1).to_string(), "1024.0 KB");
assert_eq!(FileSize::new(1024 * 1024 - 512).to_string(), "1023.5 KB");
assert_eq!(FileSize::new(1024 * 1024).to_string(), "1.0 MB");
assert_eq!(
FileSize::new(1024 * 1024 * 1022 + 513 * 1024).to_string(),
"1022.5 MB"
);
assert_eq!(FileSize::new(1024 * 1024 * 1024).to_string(), "1.0 GB");
assert_eq!(
FileSize::new(1024 * 1024 * 1024 * 1024).to_string(),
"1.0 TB"
);
assert_eq!(FileSize::new(1024 * 1024 + 5210).to_string(), "1.0 MB");
}

#[test]
fn test_clear_status_serde() {
let status = ClearStatus::Clearing;
assert_eq!(
serde_json::to_string(&status).unwrap(),
r#"{"status":"Clearing"}"#
);
let status = ClearStatus::Done(10);
assert_eq!(
serde_json::to_string(&status).unwrap(),
r#"{"status":"Done","data":10}"#
);
}
}
2 changes: 2 additions & 0 deletions src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod resource_location;
mod should_silence;
mod system_notification;
mod update_available;
mod cache;

pub use self::auto_launch::{auto_launch_setting, set_auto_launch};
pub use clipboard::copy_image;
Expand All @@ -28,3 +29,4 @@ pub use request_refer_image::request_refer_image;
pub use resource_location::{get_app_cache_path, get_app_config_path};
pub use should_silence::should_silence;
pub use system_notification::send_system_notification;
pub use cache::{get_cache_dir_size, clear_cache_dir};
6 changes: 4 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::commands::{
auto_launch_setting, back_preview, copy_image, front_logger, get_app_cache_path,
get_app_config_path, get_item, get_monitor_info, hide_notification, is_debug, message_beep,
quit, read_detail, request_refer_image, send_request, send_system_notification,
set_auto_launch, set_item, should_silence,
set_auto_launch, set_item, should_silence, get_cache_dir_size, clear_cache_dir,
};
use crate::setup::logger::init_logger;
use crate::setup::system_tray::new_system_tray;
Expand Down Expand Up @@ -76,7 +76,9 @@ fn main() {
hide_notification,
is_debug,
send_system_notification,
should_silence
should_silence,
get_cache_dir_size,
clear_cache_dir,
]);

let app = builder
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"fullscreen": false,
"visible": false,
"label": "main",
"height": 640,
"height": 720,
"resizable": true,
"title": "小刻食堂",
"width": 1280,
Expand Down
19 changes: 19 additions & 0 deletions src/api/operations/operate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ import {Cookie} from "../resourceFetcher/cookieList";
import {invoke} from "@tauri-apps/api";
import notification from "./notification";

export type Done = {
status: "Done";
data: number;
}

export type Clearing = {
status: "Clearing";
}

export type ClearStatus = Done | Clearing;

class Operate {
async openNotificationWindow(cookie: Cookie) {
console.log(`send Notification`);
Expand Down Expand Up @@ -87,6 +98,14 @@ class Operate {
async hideNotifyIcon() {
await invoke("hide_notification")
}

async getCacheDirSize() {
return await invoke<string>("get_cache_dir_size")
}

async clearCacheDir() {
return await invoke<ClearStatus>("clear_cache_dir")
}
}

const operate = new Operate();
Expand Down
Loading