use crate::error::{Error, Result};
use crate::lsp::transport::read_message;
use serde_json::Value;
use std::io::{self, BufReader, Read};
use std::net::Shutdown;
use std::os::unix::net::UnixStream;
use std::time::Instant;
const DEADLINE_MESSAGE: &str = "daemon client did not send its first message before the deadline";
pub(super) struct SocketReader {
reader: BufReader<DeadlineSocket>,
}
impl SocketReader {
pub(super) fn new(socket: UnixStream, deadline: Option<Instant>) -> Self {
Self {
reader: BufReader::new(DeadlineSocket { socket, deadline }),
}
}
pub(super) fn next_message(&mut self) -> Result<Option<Value>> {
let message = read_message(&mut self.reader);
let socket = self.reader.get_mut();
if let Some(deadline) = socket.deadline {
let finish = if Instant::now() >= deadline {
Err(Error::lsp(DEADLINE_MESSAGE))
} else {
socket.socket.set_read_timeout(None).map_err(|error| {
Error::unexpected(format!(
"failed to clear daemon client handshake timeout: {error}"
))
})
};
if finish.is_err() || !matches!(&message, Ok(Some(_))) {
let _ = socket.socket.shutdown(Shutdown::Both);
}
finish?;
socket.deadline = None;
}
message
}
}
struct DeadlineSocket {
socket: UnixStream,
deadline: Option<Instant>,
}
impl Read for DeadlineSocket {
fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
if let Some(deadline) = self.deadline {
let remaining = deadline.saturating_duration_since(Instant::now());
if remaining.is_zero() {
return Err(io::Error::new(io::ErrorKind::TimedOut, DEADLINE_MESSAGE));
}
self.socket.set_read_timeout(Some(remaining))?;
}
self.socket.read(buffer)
}
}
#[cfg(test)]
mod tests;