1use crate::{SocketRequest, SocketResponse};
2use std::io::{self, BufRead, BufReader, ErrorKind, Read, Write};
3use std::net::Shutdown;
4use std::os::unix::net::UnixStream;
5use std::path::Path;
6use std::time::Duration;
7
8const RESPONSE_LIMIT: u64 = 64 * 1024;
9
10pub fn socket_is_listening(socket_path: &Path) -> io::Result<bool> {
11 match UnixStream::connect(socket_path) {
12 Ok(_) => Ok(true),
13 Err(error)
14 if matches!(
15 error.kind(),
16 ErrorKind::NotFound | ErrorKind::ConnectionRefused
17 ) || error.raw_os_error() == Some(libc::ENOTSOCK) =>
18 {
19 Ok(false)
20 }
21 Err(error) => Err(io::Error::new(
22 error.kind(),
23 format!("cannot check {}: {error}", socket_path.display()),
24 )),
25 }
26}
27
28pub fn send_socket_request(socket_path: &Path, request: &SocketRequest) -> io::Result<String> {
29 let mut stream = UnixStream::connect(socket_path).map_err(|error| {
30 io::Error::new(
31 error.kind(),
32 format!(
33 "cannot connect to {}: {error}; is a receiving Helix session running?",
34 socket_path.display()
35 ),
36 )
37 })?;
38 stream.set_read_timeout(Some(Duration::from_secs(10)))?;
39 stream.set_write_timeout(Some(Duration::from_secs(10)))?;
40
41 serde_json::to_writer(&mut stream, request)
42 .map_err(|error| io::Error::new(ErrorKind::InvalidData, error))?;
43 stream.write_all(b"\n")?;
44 stream.flush()?;
45 stream.shutdown(Shutdown::Write)?;
46
47 let mut response_bytes = Vec::new();
48 BufReader::new(stream)
49 .take(RESPONSE_LIMIT + 1)
50 .read_until(b'\n', &mut response_bytes)?;
51 if response_bytes.len() as u64 > RESPONSE_LIMIT {
52 return Err(io::Error::new(
53 ErrorKind::InvalidData,
54 "bridge response was unexpectedly large",
55 ));
56 }
57 if response_bytes.is_empty() {
58 return Err(io::Error::new(
59 ErrorKind::UnexpectedEof,
60 "bridge closed the connection without a response",
61 ));
62 }
63
64 let response: SocketResponse = serde_json::from_slice(&response_bytes)
65 .map_err(|error| io::Error::new(ErrorKind::InvalidData, error))?;
66 if response.ok {
67 Ok(response.message)
68 } else {
69 Err(io::Error::other(response.message))
70 }
71}