lean_ctx/core/agents/
persistence.rs1use super::AgentRegistry;
2use std::path::PathBuf;
3
4pub(super) fn agents_dir() -> Result<PathBuf, String> {
5 let dir = crate::core::data_dir::lean_ctx_data_dir()?;
6 Ok(dir.join("agents"))
7}
8
9pub(super) fn mutate_persistent<T>(
10 mutate: impl FnOnce(&mut AgentRegistry) -> T,
11) -> Result<T, String> {
12 let dir = agents_dir()?;
13 std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?;
14 let _lock = FileLock::acquire(&dir.join("registry.lock"))?;
15 let path = dir.join("registry.json");
16 let mut registry = std::fs::read_to_string(&path)
17 .ok()
18 .and_then(|content| serde_json::from_str(&content).ok())
19 .unwrap_or_default();
20 let result = mutate(&mut registry);
21 let json = serde_json::to_string_pretty(®istry).map_err(|e| e.to_string())?;
22 std::fs::write(path, json).map_err(|e| e.to_string())?;
23 Ok(result)
24}
25
26pub(super) fn generate_short_id() -> String {
27 use std::collections::hash_map::DefaultHasher;
28 use std::hash::{Hash, Hasher};
29 use std::time::SystemTime;
30
31 let mut hasher = DefaultHasher::new();
32 SystemTime::now().hash(&mut hasher);
33 std::process::id().hash(&mut hasher);
34 format!("{:08x}", hasher.finish() as u32)
35}
36
37pub fn is_process_alive(pid: u32) -> bool {
45 crate::ipc::process::is_alive(pid)
46}
47
48pub(crate) struct FileLock {
49 path: PathBuf,
50}
51
52impl FileLock {
53 pub(crate) fn acquire(path: &std::path::Path) -> Result<Self, String> {
54 for _ in 0..50 {
55 if std::fs::OpenOptions::new()
56 .write(true)
57 .create_new(true)
58 .open(path)
59 .is_ok()
60 {
61 return Ok(Self {
62 path: path.to_path_buf(),
63 });
64 }
65 if let Ok(metadata) = std::fs::metadata(path)
66 && let Ok(modified) = metadata.modified()
67 && modified.elapsed().unwrap_or_default().as_secs() > 5
68 {
69 let _ = std::fs::remove_file(path);
70 continue;
71 }
72 std::thread::sleep(std::time::Duration::from_millis(100));
73 }
74 Err("Could not acquire lock after 5 seconds".to_string())
75 }
76}
77
78impl Drop for FileLock {
79 fn drop(&mut self) {
80 let _ = std::fs::remove_file(&self.path);
81 }
82}