use std::io::{BufRead, BufReader, Write};
use std::os::unix::net::UnixStream;
use std::time::{Duration, Instant};
use crate::daemon::protocol::{self, Request, Response};
const SPINNER: &[char] = &['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
pub fn try_request(request: &Request) -> Option<Response> {
let socket_path = protocol::default_socket_path();
if !socket_path.exists() {
return None;
}
let stream = match UnixStream::connect(&socket_path) {
Ok(s) => s,
Err(_) => {
let start = Instant::now();
let timeout = Duration::from_secs(120);
let mut spin_idx = 0;
loop {
eprint!(
"\r{} Waiting for daemon...",
SPINNER[spin_idx % SPINNER.len()]
);
spin_idx += 1;
std::thread::sleep(Duration::from_millis(100));
if let Ok(s) = UnixStream::connect(&socket_path) {
eprint!("\r \r");
break s;
}
if start.elapsed() > timeout {
eprint!("\r \r");
return None;
}
}
}
};
stream
.set_read_timeout(Some(Duration::from_secs(600)))
.ok()?;
stream
.set_write_timeout(Some(Duration::from_secs(5)))
.ok()?;
let json = serde_json::to_string(request).ok()?;
let mut writer = &stream;
writeln!(writer, "{json}").ok()?;
stream.set_nonblocking(true).ok()?;
let mut reader = BufReader::new(&stream);
let mut line = String::new();
let mut spin_idx = 0;
loop {
match reader.read_line(&mut line) {
Ok(0) => return None, Ok(_) => {
eprint!("\r \r");
break;
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
eprint!(
"\r{} Waiting for daemon...",
SPINNER[spin_idx % SPINNER.len()]
);
spin_idx += 1;
std::thread::sleep(Duration::from_millis(100));
}
Err(_) => return None,
}
}
serde_json::from_str(line.trim()).ok()
}
#[allow(dead_code)]
pub fn is_daemon_running() -> bool {
try_request(&Request::Ping)
.map(|r| r.success)
.unwrap_or(false)
}