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