1use crate::error::Result;
7use crate::server::ipc::{IpcCommand, IpcResponse};
8use std::path::PathBuf;
9use tokio::io::{AsyncReadExt, AsyncWriteExt};
10
11pub struct IpcClient {
13 socket_path: PathBuf,
14}
15
16impl IpcClient {
17 pub fn new(_state_dir: PathBuf) -> Self {
19 #[cfg(unix)]
20 let socket_path = _state_dir.join("irosh.sock");
21 #[cfg(windows)]
22 let socket_path = {
23 use std::hash::{Hash, Hasher};
24 let mut hasher = std::collections::hash_map::DefaultHasher::new();
25 _state_dir.hash(&mut hasher);
26 let hash = hasher.finish();
27 PathBuf::from(format!(r"\\.\pipe\irosh-service-{:x}", hash))
28 };
29
30 Self { socket_path }
31 }
32
33 pub async fn send(&self, command: IpcCommand) -> Result<IpcResponse> {
35 let mut stream = self.connect().await?;
36
37 let buf = serde_json::to_vec(&command).map_err(|e| {
38 crate::error::IroshError::Io(std::io::Error::new(std::io::ErrorKind::InvalidData, e))
39 })?;
40
41 stream.write_all(&buf).await?;
42 #[cfg(unix)]
45 stream.shutdown().await?;
46
47 let mut res_buf = Vec::new();
48 stream.read_to_end(&mut res_buf).await?;
49
50 let response: IpcResponse = serde_json::from_slice(&res_buf).map_err(|e| {
51 crate::error::IroshError::Io(std::io::Error::new(std::io::ErrorKind::InvalidData, e))
52 })?;
53
54 Ok(response)
55 }
56
57 #[cfg(unix)]
58 async fn connect(&self) -> Result<tokio::net::UnixStream> {
59 tokio::net::UnixStream::connect(&self.socket_path)
60 .await
61 .map_err(crate::error::IroshError::Io)
62 }
63
64 #[cfg(windows)]
65 async fn connect(&self) -> Result<tokio::net::windows::named_pipe::NamedPipeClient> {
66 use tokio::net::windows::named_pipe::ClientOptions;
67
68 let client = ClientOptions::new()
69 .open(&*self.socket_path.to_string_lossy())
70 .map_err(crate::error::IroshError::Io)?;
71
72 Ok(client)
73 }
74}