Skip to main content

greplm_core/
client.rs

1//! Client for the greplm daemon.
2
3#[cfg(unix)]
4pub use unix_impl::Client;
5
6#[cfg(not(unix))]
7pub use stub_impl::Client;
8
9// The daemon is built on Unix domain sockets and is unavailable on other
10// platforms. This stub lets the CLI compile everywhere; `try_connect` always
11// returns `None`, so callers transparently fall back to in-process queries.
12#[cfg(not(unix))]
13mod stub_impl {
14    use std::path::Path;
15
16    use crate::error::{Error, Result};
17    use crate::proto::{Request, Response};
18
19    /// A connected client to a running greplm daemon (unsupported on this platform).
20    pub struct Client {
21        _private: (),
22    }
23
24    impl Client {
25        /// Always returns `None`: no daemon is available on this platform.
26        pub fn try_connect(_socket: &Path) -> Option<Client> {
27            None
28        }
29
30        /// Always errors: no daemon is available on this platform.
31        pub fn request(&mut self, _req: &Request) -> Result<Response> {
32            Err(Error::other(
33                "greplm daemon is not supported on this platform",
34            ))
35        }
36    }
37}
38
39#[cfg(unix)]
40mod unix_impl {
41    use std::io::{BufRead, BufReader, Write};
42    use std::os::unix::net::UnixStream;
43    use std::path::Path;
44
45    use crate::error::{Error, Result};
46    use crate::proto::{Request, Response};
47
48    /// A connected client to a running greplm daemon.
49    pub struct Client {
50        reader: BufReader<UnixStream>,
51        writer: UnixStream,
52    }
53
54    impl Client {
55        /// Connect to a daemon listening on `socket`. Returns `None` if no daemon
56        /// is reachable (so callers can fall back to in-process queries).
57        pub fn try_connect(socket: &Path) -> Option<Client> {
58            let stream = UnixStream::connect(socket).ok()?;
59            let reader = BufReader::new(stream.try_clone().ok()?);
60            Some(Client {
61                reader,
62                writer: stream,
63            })
64        }
65
66        /// Send a request and read the response.
67        pub fn request(&mut self, req: &Request) -> Result<Response> {
68            let mut bytes = serde_json::to_vec(req)?;
69            bytes.push(b'\n');
70            self.writer.write_all(&bytes).map_err(Error::PlainIo)?;
71            self.writer.flush().map_err(Error::PlainIo)?;
72            let mut line = String::new();
73            let n = self.reader.read_line(&mut line).map_err(Error::PlainIo)?;
74            if n == 0 {
75                return Err(Error::other("daemon closed connection"));
76            }
77            let resp: Response = serde_json::from_str(line.trim())?;
78            Ok(resp)
79        }
80    }
81}