1pub mod process;
2
3#[cfg(unix)]
4mod unix;
5#[cfg(windows)]
6mod windows;
7#[cfg(windows)]
8pub use windows::NamedPipeListener;
9
10#[cfg(unix)]
11use std::path::PathBuf;
12
13use anyhow::Result;
14
15#[derive(Debug, Clone)]
17pub enum DaemonAddr {
18 #[cfg(unix)]
19 Unix(PathBuf),
20 #[cfg(windows)]
21 NamedPipe(String),
22}
23
24impl DaemonAddr {
25 pub fn default_for_current_os() -> Self {
26 #[cfg(unix)]
27 {
28 Self::Unix(unix::default_socket_path())
29 }
30 #[cfg(windows)]
31 {
32 Self::NamedPipe(windows::default_pipe_name())
33 }
34 }
35
36 pub fn display(&self) -> String {
37 match self {
38 #[cfg(unix)]
39 Self::Unix(p) => p.display().to_string(),
40 #[cfg(windows)]
41 Self::NamedPipe(n) => n.clone(),
42 }
43 }
44
45 pub fn is_listening(&self) -> bool {
47 match self {
48 #[cfg(unix)]
49 Self::Unix(p) => p.exists(),
50 #[cfg(windows)]
51 Self::NamedPipe(name) => windows::pipe_exists(name),
52 }
53 }
54}
55
56pub fn cleanup(addr: &DaemonAddr) {
58 match addr {
59 #[cfg(unix)]
60 DaemonAddr::Unix(p) => {
61 if p.exists() {
62 let _ = std::fs::remove_file(p);
63 }
64 }
65 #[cfg(windows)]
66 DaemonAddr::NamedPipe(_) => {
67 }
69 }
70}
71
72#[cfg(unix)]
74pub fn bind_listener(addr: &DaemonAddr) -> Result<tokio::net::UnixListener> {
75 match addr {
76 DaemonAddr::Unix(path) => unix::bind_listener(path),
77 }
78}
79
80#[cfg(unix)]
82pub async fn connect(addr: &DaemonAddr) -> Result<tokio::net::UnixStream> {
83 match addr {
84 DaemonAddr::Unix(path) => unix::connect(path).await,
85 }
86}
87
88#[cfg(windows)]
90pub fn bind_listener(addr: &DaemonAddr) -> Result<NamedPipeListener> {
91 match addr {
92 DaemonAddr::NamedPipe(name) => NamedPipeListener::bind(name),
93 }
94}
95
96#[cfg(windows)]
98pub async fn connect(
99 addr: &DaemonAddr,
100) -> Result<tokio::net::windows::named_pipe::NamedPipeClient> {
101 match addr {
102 DaemonAddr::NamedPipe(name) => windows::connect(name).await,
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn daemon_addr_display_non_empty() {
112 let addr = DaemonAddr::default_for_current_os();
113 let display = addr.display();
114 assert!(!display.is_empty());
115 }
116
117 #[test]
118 fn cleanup_nonexistent_does_not_panic() {
119 #[cfg(unix)]
120 {
121 let addr = DaemonAddr::Unix(std::path::PathBuf::from(
122 "/tmp/lean-ctx-test-nonexistent.sock",
123 ));
124 cleanup(&addr);
125 }
126 }
127}