linux_ipc/
lib.rs

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}