1use crate::core::config::Config;
2use crate::core::error::{Error, Result};
3use std::process::{Command, Stdio};
4
5pub fn is_running() -> Result<bool> {
7 let pid_path = Config::pid_path()?;
8 if !pid_path.exists() {
9 return Ok(false);
10 }
11
12 let pid_str = std::fs::read_to_string(&pid_path)?;
13 let pid: u32 = pid_str.trim().parse().unwrap_or(0);
14
15 if pid == 0 {
16 return Ok(false);
17 }
18
19 #[cfg(unix)]
21 {
22 let result = unsafe { libc::kill(pid as i32, 0) };
23 Ok(result == 0)
24 }
25
26 #[cfg(windows)]
27 {
28 let output = Command::new("tasklist")
30 .args(["/FI", &format!("PID eq {}", pid), "/NH"])
31 .output();
32
33 match output {
34 Ok(out) => {
35 let stdout = String::from_utf8_lossy(&out.stdout);
36 Ok(stdout.contains(&pid.to_string()))
37 }
38 Err(_) => Ok(false),
39 }
40 }
41}
42
43pub fn get_pid() -> Result<Option<u32>> {
45 let pid_path = Config::pid_path()?;
46 if !pid_path.exists() {
47 return Ok(None);
48 }
49
50 let pid_str = std::fs::read_to_string(&pid_path)?;
51 let pid: u32 = pid_str.trim().parse().unwrap_or(0);
52
53 if pid == 0 {
54 return Ok(None);
55 }
56
57 Ok(Some(pid))
58}
59
60pub fn start_daemon() -> Result<u32> {
62 if is_running()? {
63 if let Some(pid) = get_pid()? {
64 return Err(Error::DaemonError {
65 message: format!("Daemon already running with PID {}", pid),
66 });
67 }
68 }
69
70 Config::ensure_home()?;
71
72 let exe = std::env::current_exe()?;
74
75 #[cfg(unix)]
77 let child = Command::new(&exe)
78 .arg("__daemon")
79 .stdin(Stdio::null())
80 .stdout(Stdio::null())
81 .stderr(Stdio::null())
82 .spawn()?;
83
84 #[cfg(windows)]
85 let child = Command::new(&exe)
86 .arg("__daemon")
87 .creation_flags(0x00000008) .stdin(Stdio::null())
89 .stdout(Stdio::null())
90 .stderr(Stdio::null())
91 .spawn()?;
92
93 let pid = child.id();
94
95 let pid_path = Config::pid_path()?;
97 std::fs::write(&pid_path, pid.to_string())?;
98
99 std::thread::sleep(std::time::Duration::from_millis(100));
101
102 Ok(pid)
103}
104
105pub fn stop_daemon() -> Result<bool> {
107 let pid = match get_pid()? {
108 Some(p) => p,
109 None => return Ok(false),
110 };
111
112 #[cfg(unix)]
113 {
114 unsafe {
115 libc::kill(pid as i32, libc::SIGTERM);
116 }
117 }
118
119 #[cfg(windows)]
120 {
121 let _ = Command::new("taskkill")
123 .args(["/PID", &pid.to_string(), "/F"])
124 .output();
125 }
126
127 let pid_path = Config::pid_path()?;
129 if pid_path.exists() {
130 let _ = std::fs::remove_file(&pid_path);
131 }
132
133 #[cfg(unix)]
134 {
135 let socket_path = Config::socket_path()?;
136 if socket_path.exists() {
137 let _ = std::fs::remove_file(&socket_path);
138 }
139 }
140
141 #[cfg(windows)]
142 {
143 let port_path = Config::port_path()?;
144 if port_path.exists() {
145 let _ = std::fs::remove_file(&port_path);
146 }
147 }
148
149 Ok(true)
150}