ai_agent/utils/plugins/
cache_utils.rs1#![allow(dead_code)]
3
4use std::collections::HashSet;
5use std::path::{Path, PathBuf};
6use std::sync::OnceLock;
7use std::time::{SystemTime, UNIX_EPOCH};
8
9use tokio::fs;
10
11use super::installed_plugins_manager::load_installed_plugins_from_disk;
12use super::loader::{clear_plugin_cache, get_plugin_cache_path};
13
14const ORPHANED_AT_FILENAME: &str = ".orphaned_at";
15const CLEANUP_AGE_MS: u64 = 7 * 24 * 60 * 60 * 1000; pub fn clear_all_plugin_caches() {
19 clear_plugin_cache(None);
20 crate::utils::plugins::load_plugin_hooks::clear_plugin_hook_cache();
21 crate::utils::plugins::load_plugin_commands::clear_plugin_command_cache();
22 crate::utils::plugins::load_plugin_agents::clear_plugin_agent_cache();
23 crate::utils::plugins::load_plugin_output_styles::clear_plugin_output_style_cache();
24 crate::utils::plugins::plugin_options_storage::clear_plugin_options_cache();
25}
26
27pub fn clear_all_caches() {
29 clear_all_plugin_caches();
30}
31
32pub async fn mark_plugin_version_orphaned(
34 version_path: &Path,
35) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
36 let orphaned_at_path = version_path.join(ORPHANED_AT_FILENAME);
37 let now = SystemTime::now()
38 .duration_since(UNIX_EPOCH)
39 .unwrap_or_default()
40 .as_millis();
41 fs::write(&orphaned_at_path, now.to_string())
42 .await
43 .map_err(|e| {
44 format!(
45 "Failed to write .orphaned_at at {:?}: {}",
46 orphaned_at_path, e
47 )
48 })?;
49 Ok(())
50}
51
52pub async fn cleanup_orphaned_plugin_versions_in_background() {
54 if super::zip_cache::is_plugin_zip_cache_enabled() {
55 return;
56 }
57
58 if let Err(e) = do_cleanup().await {
59 log::debug!("Plugin cache cleanup failed: {}", e);
60 }
61}
62
63async fn do_cleanup() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
64 let installed_versions = get_installed_version_paths()?;
65 let cache_path = PathBuf::from(get_plugin_cache_path());
66 let now = SystemTime::now()
67 .duration_since(UNIX_EPOCH)
68 .unwrap_or_default()
69 .as_millis() as u64;
70
71 for version_path in &installed_versions {
73 remove_orphaned_at_marker(version_path).await;
74 }
75
76 log::debug!(
78 "Orphaned cleanup: {} installed versions, cache at {:?}",
79 installed_versions.len(),
80 cache_path
81 );
82 let _ = now; Ok(())
84}
85
86fn get_installed_version_paths()
87-> Result<HashSet<PathBuf>, Box<dyn std::error::Error + Send + Sync>> {
88 let mut paths = HashSet::new();
89 let disk_data = load_installed_plugins_from_disk()?;
90 for installations in disk_data.plugins.values() {
91 for entry in installations {
92 paths.insert(PathBuf::from(&entry.install_path));
93 }
94 }
95 Ok(paths)
96}
97
98async fn remove_orphaned_at_marker(version_path: &Path) {
99 let orphaned_at_path = version_path.join(ORPHANED_AT_FILENAME);
100 if let Err(e) = fs::remove_file(&orphaned_at_path).await {
101 if e.kind() != std::io::ErrorKind::NotFound {
102 log::debug!(
103 "Failed to remove .orphaned_at at {:?}: {}",
104 orphaned_at_path,
105 e
106 );
107 }
108 }
109}
110
111async fn _process_orphaned_plugin_version(_version_path: &Path, _now: u64) {
112 }
114
115async fn _remove_if_empty(_dir_path: &Path) {
116 }
118
119async fn _read_subdirs(
120 _dir_path: &Path,
121) -> Result<Vec<String>, Box<dyn std::error::Error + Send + Sync>> {
122 Ok(Vec::new())
123}