use std::{io::Write as _, os::unix::net::UnixStream, path::PathBuf};
use crate::{error::OhNo, protocol::response::Response};
#[derive(Debug)]
pub struct Connection {
socket: UnixStream,
}
impl Connection {
pub fn connect(session: impl AsRef<str>) -> Result<Self, OhNo> {
let path = Self::socket_path(session.as_ref())?;
let socket = UnixStream::connect(path).map_err(|err| OhNo::KakouneUnixSocketError { err })?;
Ok(Self { socket })
}
pub fn send(&mut self, resp: Response) -> Result<(), OhNo> {
let mut resp_str = String::new();
resp
.serialize_into(&mut resp_str)
.map_err(|err| OhNo::ResponseSerialization { err })?;
log::trace!("sending response back to Kakoune: {resp_str}");
let bytes = resp_str.as_bytes();
let mut content = Vec::new();
content.extend(encode_len(bytes.len()));
content.extend(bytes);
let mut message = vec![0x02];
message.extend(encode_len(content.len() + 5));
message.extend(content);
self
.socket
.write_all(&message)
.map_err(|err| OhNo::KakouneUnixSocketError { err })
}
fn socket_path(session: &str) -> Result<PathBuf, OhNo> {
let session_dir = dirs::runtime_dir()
.or_else(|| std::env::var("TMPDIR").ok().map(PathBuf::from))
.ok_or(OhNo::NoRuntimeDir)?;
Ok(session_dir.join(format!("kakoune/{session}")))
}
}
fn encode_len(size: usize) -> [u8; 4] {
(size as u32).to_ne_bytes()
}