Skip to main content

monocoque_core/
ipc.rs

1//! IPC transport via Unix domain sockets.
2//!
3//! Provides Unix domain socket support for inter-process communication
4//! with zero-copy and low-latency characteristics.
5
6#[cfg(unix)]
7use crate::rt::{UnixListener, UnixStream};
8#[cfg(unix)]
9use std::path::Path;
10
11#[cfg(unix)]
12/// Connect to a Unix domain socket.
13///
14/// # Examples
15///
16/// ```no_run
17/// use monocoque_core::ipc;
18///
19/// # async fn example() -> std::io::Result<()> {
20/// let stream = ipc::connect("/tmp/socket.sock").await?;
21/// # Ok(())
22/// # }
23/// ```
24pub async fn connect<P: AsRef<Path>>(path: P) -> std::io::Result<UnixStream> {
25    UnixStream::connect(path).await
26}
27
28#[cfg(unix)]
29/// Bind a Unix domain socket listener.
30///
31/// Returns the listener ready to accept connections.
32///
33/// # Examples
34///
35/// ```no_run
36/// use monocoque_core::ipc;
37///
38/// # async fn example() -> std::io::Result<()> {
39/// let listener = ipc::bind("/tmp/socket.sock").await?;
40/// # Ok(())
41/// # }
42/// ```
43pub async fn bind<P: AsRef<Path>>(path: P) -> std::io::Result<UnixListener> {
44    // Remove existing socket file if it exists
45    let path_ref = path.as_ref();
46    if path_ref.exists() {
47        std::fs::remove_file(path_ref)?;
48    }
49
50    UnixListener::bind(path).await
51}
52
53#[cfg(unix)]
54/// Accept a connection on a Unix domain socket listener.
55pub async fn accept(listener: &UnixListener) -> std::io::Result<UnixStream> {
56    let (stream, _addr) = listener.accept().await?;
57    Ok(stream)
58}
59
60#[cfg(test)]
61#[cfg(unix)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_ipc_connect_bind() {
67        crate::rt::LocalRuntime::new()
68            .unwrap()
69            .block_on(test_ipc_connect_bind_impl())
70    }
71
72    async fn test_ipc_connect_bind_impl() {
73        let path = "/tmp/monocoque_test_ipc.sock";
74
75        // Clean up any existing socket
76        let _ = std::fs::remove_file(path);
77
78        let listener = bind(path).await.unwrap();
79
80        // Spawn accept task
81        let accept_handle = crate::rt::spawn(async move { accept(&listener).await });
82
83        // Give listener time to start
84        crate::rt::sleep(std::time::Duration::from_millis(10)).await;
85
86        // Connect
87        let client = connect(path).await.unwrap();
88
89        // Wait for accept
90        let server = crate::rt::join(accept_handle).await.unwrap();
91
92        assert!(client.peer_addr().is_ok());
93        assert!(server.local_addr().is_ok());
94
95        // Cleanup
96        drop(client);
97        drop(server);
98        let _ = std::fs::remove_file(path);
99    }
100}