1use serde::{de::DeserializeOwned, Serialize};
2use std::{
3 fmt::Debug,
4 fs,
5 io::{self, Read, Write},
6 os::unix::net::{UnixListener, UnixStream},
7 path::PathBuf,
8};
9
10#[derive(Debug)]
11pub struct IpcChannel {
12 socket_path: PathBuf,
13 listener: Option<UnixListener>,
14 stream: Option<UnixStream>,
15 is_client: bool,
16}
17
18type ReplyFn<T> = Box<dyn FnOnce(T) -> io::Result<()>>;
19
20impl IpcChannel {
21 pub fn new(path: &str) -> io::Result<Self> {
22 fs::remove_file(path).ok();
23 let listener = Some(UnixListener::bind(path)?);
24
25 Ok(Self {
26 socket_path: PathBuf::from(path),
27 listener,
28 stream: None,
29 is_client: false,
30 })
31 }
32
33 pub fn connect(path: &str) -> io::Result<Self> {
34 let stream = Some(UnixStream::connect(path)?);
35
36 Ok(Self {
37 socket_path: PathBuf::from(path),
38 listener: None,
39 stream,
40 is_client: true,
41 })
42 }
43
44 fn get_stream(&mut self) -> io::Result<&mut UnixStream> {
45 if self.stream.is_none() {
46 let stream = UnixStream::connect(&self.socket_path)?;
47 self.stream = Some(stream);
48 }
49 self.stream
50 .as_mut()
51 .ok_or_else(|| io::Error::new(io::ErrorKind::NotConnected, "Failed to connect to stream"))
52 }
53
54 pub fn send<T: Serialize, R: DeserializeOwned + Debug>(&mut self, value: T) -> io::Result<Option<R>> {
55 let stream = self.get_stream()?;
56 let binary = bincode::serialize(&value).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
57
58 stream.write_all(&binary)?;
59 stream.flush()?;
60 stream.shutdown(std::net::Shutdown::Write)?;
61
62 let mut buffer = Vec::new();
63 stream.read_to_end(&mut buffer)?;
64
65 self.stream = None;
66
67 if buffer.is_empty() {
68 return Ok(None);
69 }
70
71 let response: R = bincode::deserialize(&buffer).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
72
73 Ok(Some(response))
74 }
75
76 pub fn receive<T: DeserializeOwned + Debug, R: Serialize>(&mut self) -> io::Result<(T, ReplyFn<R>)> {
77 let listener = self
78 .listener
79 .as_mut()
80 .ok_or_else(|| io::Error::new(io::ErrorKind::NotConnected, "Listener not found"))?;
81 let (mut stream, _) = listener.accept()?;
82
83 let mut buffer = Vec::new();
84 stream.read_to_end(&mut buffer)?;
85
86 let request: T = bincode::deserialize(&buffer).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
87
88 let reply_fn = move |value: R| {
89 let binary = bincode::serialize(&value).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
90
91 stream.write_all(&binary)?;
92 stream.flush()?;
93 Ok(())
94 };
95
96 Ok((request, Box::new(reply_fn)))
97 }
98}
99
100impl Drop for IpcChannel {
101 fn drop(&mut self) {
102 if !self.is_client {
103 fs::remove_file(&self.socket_path).ok();
104 }
105 }
106}