1use std::env;
8use std::path::PathBuf;
9
10const MAX_SOCKET_PATH_LEN: usize = 103;
12
13pub fn socket_base_dir() -> PathBuf {
16 let uid = nix::unistd::getuid();
17 PathBuf::from(format!("/tmp/agent-procs-{}", uid))
18}
19
20pub fn socket_path(session: &str) -> PathBuf {
21 let path = socket_base_dir().join(format!("{}.sock", session));
22 if path.as_os_str().len() > MAX_SOCKET_PATH_LEN {
23 tracing::warn!(
24 path = %path.display(),
25 max = MAX_SOCKET_PATH_LEN,
26 actual = path.as_os_str().len(),
27 "socket path exceeds maximum length; use a shorter session name"
28 );
29 }
30 path
31}
32
33pub fn pid_path(session: &str) -> PathBuf {
34 socket_base_dir().join(format!("{}.pid", session))
35}
36
37pub fn state_dir(session: &str) -> PathBuf {
40 let base = match env::var("XDG_STATE_HOME") {
41 Ok(dir) => PathBuf::from(dir),
42 Err(_) => {
43 let home = env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
44 PathBuf::from(home).join(".local/state")
45 }
46 };
47 base.join("agent-procs/sessions").join(session)
48}
49
50pub fn log_dir(session: &str) -> PathBuf {
51 state_dir(session).join("logs")
52}
53pub fn state_file(session: &str) -> PathBuf {
54 state_dir(session).join("state.json")
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn test_socket_base_dir_contains_uid() {
63 let uid = nix::unistd::getuid();
64 let dir = socket_base_dir();
65 let dir_str = dir.to_string_lossy();
66 assert!(
67 dir_str.contains(&uid.to_string()),
68 "socket_base_dir '{}' should contain uid '{}'",
69 dir_str,
70 uid
71 );
72 }
73
74 #[test]
75 fn test_socket_path_format() {
76 let path = socket_path("mysession");
77 let path_str = path.to_string_lossy();
78 assert!(
79 path_str.ends_with(".sock"),
80 "socket path '{}' should end with .sock",
81 path_str
82 );
83 assert!(path_str.contains("mysession"));
84 }
85
86 #[test]
87 fn test_pid_path_format() {
88 let path = pid_path("mysession");
89 let path_str = path.to_string_lossy();
90 assert!(
91 path_str.ends_with(".pid"),
92 "pid path '{}' should end with .pid",
93 path_str
94 );
95 assert!(path_str.contains("mysession"));
96 }
97
98 #[test]
99 fn test_log_dir_under_state_dir() {
100 let sdir = state_dir("test-session");
101 let ldir = log_dir("test-session");
102 assert!(
103 ldir.starts_with(&sdir),
104 "log_dir '{}' should be under state_dir '{}'",
105 ldir.display(),
106 sdir.display()
107 );
108 }
109}