From e0d26203dd42cfa7ed3ecadcad24b90b4f5d78d1 Mon Sep 17 00:00:00 2001 From: GyDi <zzzgydi@gmail.com> Date: Thu, 2 Nov 2023 20:12:46 +0800 Subject: [PATCH] feat: support auto clean log files --- src-tauri/src/config/verge.rs | 7 +- src-tauri/src/utils/init.rs | 72 ++++++++++++++++++++- src/components/setting/mods/misc-viewer.tsx | 31 ++++++++- src/locales/en.json | 8 ++- src/locales/zh.json | 8 ++- src/services/types.d.ts | 1 + 6 files changed, 121 insertions(+), 6 deletions(-) diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index 708ce61..961280e 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -83,6 +83,10 @@ pub struct IVerge { /// proxy 页é¢å¸ƒå±€ 列数 pub proxy_layout_column: Option<i32>, + /// æ—¥å¿—æ¸…ç† + /// 0: 䏿¸…ç†; 1: 7天; 2: 30天; 3: 90天 + pub auto_log_clean: Option<i32>, + /// window size and position #[serde(skip_serializing_if = "Option::is_none")] pub window_size_position: Option<Vec<f64>>, @@ -137,6 +141,7 @@ impl IVerge { auto_close_connection: Some(true), enable_builtin_enhanced: Some(true), enable_clash_fields: Some(true), + auto_log_clean: Some(3), ..Self::default() } } @@ -183,7 +188,7 @@ impl IVerge { patch!(enable_builtin_enhanced); patch!(proxy_layout_column); patch!(enable_clash_fields); - + patch!(auto_log_clean); patch!(window_size_position); } diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index 2fae79d..e9bcd42 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -1,13 +1,14 @@ use crate::config::*; use crate::utils::{dirs, help}; use anyhow::Result; -use chrono::Local; +use chrono::{DateTime, Local}; use log::LevelFilter; use log4rs::append::console::ConsoleAppender; use log4rs::append::file::FileAppender; use log4rs::config::{Appender, Logger, Root}; use log4rs::encode::pattern::PatternEncoder; -use std::fs; +use std::fs::{self, DirEntry}; +use std::str::FromStr; use tauri::PackageInfo; /// initialize this instance's log file @@ -69,6 +70,72 @@ fn init_log() -> Result<()> { Ok(()) } +/// åˆ é™¤log文件 +pub fn delete_log() -> Result<()> { + let log_dir = dirs::app_logs_dir()?; + if !log_dir.exists() { + return Ok(()); + } + + let auto_log_clean = { + let verge = Config::verge(); + let verge = verge.data(); + verge.auto_log_clean.clone().unwrap_or(0) + }; + + let day = match auto_log_clean { + 1 => 7, + 2 => 30, + 3 => 90, + _ => return Ok(()), + }; + + log::debug!(target: "app", "try to delete log files, day: {day}"); + + // %Y-%m-%d to NaiveDateTime + let parse_time_str = |s: &str| { + let sa: Vec<&str> = s.split('-').collect(); + if sa.len() != 4 { + return Err(anyhow::anyhow!("invalid time str")); + } + + let year = i32::from_str(sa[0])?; + let month = u32::from_str(sa[1])?; + let day = u32::from_str(sa[2])?; + let time = chrono::NaiveDate::from_ymd_opt(year, month, day) + .ok_or(anyhow::anyhow!("invalid time str"))? + .and_hms_opt(0, 0, 0) + .ok_or(anyhow::anyhow!("invalid time str"))?; + Ok(time) + }; + + let process_file = |file: DirEntry| -> Result<()> { + let file_name = file.file_name(); + let file_name = file_name.to_str().unwrap_or_default(); + + if file_name.ends_with(".log") { + let now = Local::now(); + let created_time = parse_time_str(&file_name[0..file_name.len() - 4])?; + let file_time = DateTime::<Local>::from_local(created_time, now.offset().clone()); + + let duration = now.signed_duration_since(file_time); + if duration.num_days() > day { + let file_path = file.path(); + let _ = fs::remove_file(file_path); + log::info!(target: "app", "delete log file: {file_name}"); + } + } + Ok(()) + }; + + for file in fs::read_dir(&log_dir)? { + if let Ok(file) = file { + let _ = process_file(file); + } + } + Ok(()) +} + /// Initialize all the config files /// before tauri setup pub fn init_config() -> Result<()> { @@ -78,6 +145,7 @@ pub fn init_config() -> Result<()> { } let _ = init_log(); + let _ = delete_log(); crate::log_err!(dirs::app_home_dir().map(|app_dir| { if !app_dir.exists() { diff --git a/src/components/setting/mods/misc-viewer.tsx b/src/components/setting/mods/misc-viewer.tsx index cfcd1c0..7d63264 100644 --- a/src/components/setting/mods/misc-viewer.tsx +++ b/src/components/setting/mods/misc-viewer.tsx @@ -25,6 +25,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => { enableBuiltinEnhanced: true, proxyLayoutColumn: 6, defaultLatencyTest: "", + autoLogClean: 0, }); useImperativeHandle(ref, () => ({ @@ -37,6 +38,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => { enableBuiltinEnhanced: verge?.enable_builtin_enhanced ?? true, proxyLayoutColumn: verge?.proxy_layout_column || 6, defaultLatencyTest: verge?.default_latency_test || "", + autoLogClean: verge?.auto_log_clean || 0, }); }, close: () => setOpen(false), @@ -51,6 +53,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => { enable_builtin_enhanced: values.enableBuiltinEnhanced, proxy_layout_column: values.proxyLayoutColumn, default_latency_test: values.defaultLatencyTest, + auto_log_clean: values.autoLogClean as any, }); setOpen(false); } catch (err: any) { @@ -128,7 +131,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => { <ListItemText primary={t("Proxy Layout Column")} /> <Select size="small" - sx={{ width: 100, "> div": { py: "7.5px" } }} + sx={{ width: 135, "> div": { py: "7.5px" } }} value={values.proxyLayoutColumn} onChange={(e) => { setValues((v) => ({ @@ -148,6 +151,32 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => { </Select> </ListItem> + <ListItem sx={{ padding: "5px 2px" }}> + <ListItemText primary={t("Auto Log Clean")} /> + <Select + size="small" + sx={{ width: 135, "> div": { py: "7.5px" } }} + value={values.autoLogClean} + onChange={(e) => { + setValues((v) => ({ + ...v, + autoLogClean: e.target.value as number, + })); + }} + > + {[ + { key: "Never Clean", value: 0 }, + { key: "Retain 7 Days", value: 1 }, + { key: "Retain 30 Days", value: 2 }, + { key: "Retain 90 Days", value: 3 }, + ].map((i) => ( + <MenuItem key={i.value} value={i.value}> + {t(i.key)} + </MenuItem> + ))} + </Select> + </ListItem> + <ListItem sx={{ padding: "5px 2px" }}> <ListItemText primary={t("Default Latency Test")} /> <TextField diff --git a/src/locales/en.json b/src/locales/en.json index 3ea7b21..10c92ef 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -125,5 +125,11 @@ "Enable Clash Fields Filter": "Enable Clash Fields Filter", "Enable Builtin Enhanced": "Enable Builtin Enhanced", "Proxy Layout Column": "Proxy Layout Column", - "Default Latency Test": "Default Latency Test" + "Default Latency Test": "Default Latency Test", + + "Auto Log Clean": "Auto Log Clean", + "Never Clean": "Never Clean", + "Retain 7 Days": "Retain 7 Days", + "Retain 30 Days": "Retain 30 Days", + "Retain 90 Days": "Retain 90 Days" } diff --git a/src/locales/zh.json b/src/locales/zh.json index 256ce8c..27b358c 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -125,5 +125,11 @@ "Enable Clash Fields Filter": "å¼€å¯Clashå—æ®µè¿‡æ»¤", "Enable Builtin Enhanced": "å¼€å¯å†…建增强功能", "Proxy Layout Column": "代ç†é¡µå¸ƒå±€åˆ—æ•°", - "Default Latency Test": "默认测试链接" + "Default Latency Test": "默认测试链接", + + "Auto Log Clean": "è‡ªåŠ¨æ¸…ç†æ—¥å¿—", + "Never Clean": "䏿¸…ç†", + "Retain 7 Days": "ä¿ç•™7天", + "Retain 30 Days": "ä¿ç•™30天", + "Retain 90 Days": "ä¿ç•™90天" } diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 57e3316..3fe2175 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -186,6 +186,7 @@ interface IVergeConfig { default_latency_test?: string; enable_clash_fields?: boolean; enable_builtin_enhanced?: boolean; + auto_log_clean?: 0 | 1 | 2 | 3; proxy_layout_column?: number; } -- GitLab