use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
net::UnixStream,
};
use crate::protocol::{Request, Response};
use crate::runtime::RuntimePaths;
#[derive(Debug)]
pub struct Client {
socket_path: PathBuf,
}
impl Client {
pub fn new() -> Self {
Self::for_socket(RuntimePaths::default().socket)
}
pub fn for_socket(socket_path: impl Into<PathBuf>) -> Self {
Self {
socket_path: socket_path.into(),
}
}
pub async fn send(&self, request: Request) -> Result<Response> {
send_to_socket(&self.socket_path, request).await
}
}
impl Default for Client {
fn default() -> Self {
Self::new()
}
}
pub async fn send_to_socket(socket_path: &Path, request: Request) -> Result<Response> {
let stream = UnixStream::connect(socket_path).await.with_context(|| {
format!(
"failed to connect to pz daemon at {}",
socket_path.display()
)
})?;
let (reader, mut writer) = stream.into_split();
let mut reader = BufReader::new(reader);
let mut response = String::new();
let request = serde_json::to_vec(&request).context("failed to encode request")?;
writer
.write_all(&request)
.await
.context("failed to send request")?;
writer
.write_all(b"\n")
.await
.context("failed to finish request")?;
reader
.read_line(&mut response)
.await
.context("failed to read daemon response")?;
serde_json::from_str(&response).context("failed to decode daemon response")
}