use crate::{SocketRequest, SocketResponse};
use std::io::{self, BufRead, BufReader, ErrorKind, Read, Write};
use std::net::Shutdown;
use std::os::unix::net::UnixStream;
use std::path::Path;
use std::time::Duration;
const RESPONSE_LIMIT: u64 = 64 * 1024;
pub fn socket_is_listening(socket_path: &Path) -> io::Result<bool> {
match UnixStream::connect(socket_path) {
Ok(_) => Ok(true),
Err(error)
if matches!(
error.kind(),
ErrorKind::NotFound | ErrorKind::ConnectionRefused
) || error.raw_os_error() == Some(libc::ENOTSOCK) =>
{
Ok(false)
}
Err(error) => Err(io::Error::new(
error.kind(),
format!("cannot check {}: {error}", socket_path.display()),
)),
}
}
pub fn send_socket_request(socket_path: &Path, request: &SocketRequest) -> io::Result<String> {
let mut stream = UnixStream::connect(socket_path).map_err(|error| {
io::Error::new(
error.kind(),
format!(
"cannot connect to {}: {error}; is a receiving Helix session running?",
socket_path.display()
),
)
})?;
stream.set_read_timeout(Some(Duration::from_secs(10)))?;
stream.set_write_timeout(Some(Duration::from_secs(10)))?;
serde_json::to_writer(&mut stream, request)
.map_err(|error| io::Error::new(ErrorKind::InvalidData, error))?;
stream.write_all(b"\n")?;
stream.flush()?;
stream.shutdown(Shutdown::Write)?;
let mut response_bytes = Vec::new();
BufReader::new(stream)
.take(RESPONSE_LIMIT + 1)
.read_until(b'\n', &mut response_bytes)?;
if response_bytes.len() as u64 > RESPONSE_LIMIT {
return Err(io::Error::new(
ErrorKind::InvalidData,
"bridge response was unexpectedly large",
));
}
if response_bytes.is_empty() {
return Err(io::Error::new(
ErrorKind::UnexpectedEof,
"bridge closed the connection without a response",
));
}
let response: SocketResponse = serde_json::from_slice(&response_bytes)
.map_err(|error| io::Error::new(ErrorKind::InvalidData, error))?;
if response.ok {
Ok(response.message)
} else {
Err(io::Error::other(response.message))
}
}