use md5::{Digest, Md5};
use std::time::SystemTime;
pub fn file_mtime(path: &str) -> Option<SystemTime> {
std::fs::metadata(path).and_then(|m| m.modified()).ok()
}
pub fn is_cache_entry_stale(path: &str, cached_mtime: Option<SystemTime>) -> bool {
let current = file_mtime(path);
match (cached_mtime, current) {
(None, None) => false,
(Some(_), None) | (None, Some(_)) => true,
(Some(cached), Some(current)) => current != cached,
}
}
const VERIFY_HASH_CAP_BYTES: u64 = 8 * 1024 * 1024;
fn cache_verify_enabled() -> bool {
std::env::var("LEAN_CTX_CACHE_VERIFY").map_or(true, |v| v != "0")
}
pub fn is_cache_entry_stale_verified(
path: &str,
cached_mtime: Option<SystemTime>,
cached_hash: &str,
) -> bool {
if is_cache_entry_stale(path, cached_mtime) {
return true;
}
if cached_hash.is_empty() || !cache_verify_enabled() {
return false;
}
let Ok(meta) = std::fs::metadata(path) else {
return true;
};
if meta.len() > VERIFY_HASH_CAP_BYTES {
return false;
}
match std::fs::read(path) {
Ok(bytes) => compute_md5(&String::from_utf8_lossy(&bytes)) != cached_hash,
Err(_) => true,
}
}
pub(super) fn compute_md5(content: &str) -> String {
let mut hasher = Md5::new();
hasher.update(content.as_bytes());
crate::core::agent_identity::hex_encode(&hasher.finalize())
}