ipcez
Rust library for inter-process communication (IPC) with deployment and platform flexibility: it detects whether the process you talk to is local or remote and picks the right transport (WebSocket, Unix domain socket, or Windows named pipe) based on the operating system and backend deployment.
Recommendation: Use socket_init(endpoint) (see Socket API): pass one endpoint string and set target / os in the environment for local connections, or use a ws:// / wss:// URL for remote. You do not need to know which transport is used.
Requirements
- Rust 1.93+ (edition 2024)
- Tokio runtime when using the async socket API (ipcez depends on tokio)
Installation
Add to your Cargo.toml:
[]
= "0.1"
If you use socket_init, ensure your binary has a Tokio runtime (e.g. #[tokio::main] or tokio::runtime::Runtime).
Environment variables
The library uses two optional environment variables to choose transport. Set them in your deployment or config so the same binary can run locally or remotely.
| Variable | Allowed values | Meaning |
|---|---|---|
os |
linux, windows |
Operating system (case-insensitive). |
target |
local, remote |
Whether the other process is on this machine or a remote server. |
For local endpoints, socket_init(endpoint) reads them automatically and returns a clear error (SocketError::Detection) if os or target is missing or invalid (the error message states which variable is the problem and, for invalid values, what is expected). When detection fails, the library also prints guidance to the console (stderr) explaining the missing or invalid variable and what to do to fix it.
Socket API
Socket API
You connect with one function and one endpoint string. Set the target and os environment variables for local connections; use a WebSocket URL for remote. No need to know which transport (WebSocket, Unix socket, or named pipe) is used.
Endpoint rule:
- URL (
ws://orwss://) → connects as remote (WebSocket). - Otherwise → treated as local: the library reads
targetandosfrom the environment. On Windows (local), if the string does not start with\\.\pipe\, that prefix is added automatically.
Rust: socket_init(endpoint). Node/TS: connect(addr). Python: ipcez.connect(addr). C#: Ipcez.Connect(addr).
Rust example:
use ;
use mpsc;
async
Python example:
=
=
=
Transport selection
socket_init(endpoint) resolves transport from the endpoint and (for local) from the target and os environment variables:
| Target | OS | Transport | Endpoint format |
|---|---|---|---|
| Remote | any | WebSocket | ws://host:port/path or wss://... |
| Local | Linux | Unix domain socket | Socket path, e.g. /tmp/ipcez.sock |
| Local | Windows | Named pipe | \\.\pipe\pipename or just pipename |
Unsupported combinations (e.g. local + Linux on a Windows build) return SocketError::UnsupportedCombination(target, os).
Address format by transport
- WebSocket (remote): Full URL. Use
ws://for plain,wss://for TLS. - Unix (local + Linux): Absolute or relative path to the socket file (e.g.
/tmp/ipcez.sock). - Named pipe (local + Windows): Either the full path
\\.\pipe\pipenameor onlypipename; the library prefixes\\.\pipe\when needed. After eachsend_message(), the library signals the named eventGlobal\pipename.data_readyso a receiver can wait on it before reading, then waits up to 5 seconds for the receiver to signalGlobal\pipename.data_ackedto confirm receipt. External recipients must signal the same-named "data acked" event after each successful read.
Using the socket
Socket exposes a message API:
send_message(&self, msg: &[u8])— sends one message (async). Message length is limited to 4 MiB. For local transports, the call waits up to 5 seconds for the recipient to signal "data acked" (named event on Windows, named semaphore on Linux); if no ack is received, returnsSocketError::RecipientAckTimeout. The recipient (e.g.message_handleror an external process) must signal the "data acked" event/semaphore after each successful read.message_handler(&self, callback)— invokes an async callback for each incoming message. The callback receivesResult<Vec<u8>, SocketError>:Ok(msg)for each message, andErr(e)once when the read loop fails (e.g. connection lost), then the handler task stops.disconnect()— closes the connection (async). After calling it,send_message()and themessage_handlercallback will see a connection-lost error; the handler task then stops.
Example: send a message and handle incoming messages with a channel:
use ;
use mpsc;
async
Connection loss (all transports)
For local connections (Unix domain socket and Windows named pipe), the library runs a liveness check (default 10 ms) on the read path. When the peer disconnects, message_handler receives one Err(SocketError::Io(...)) (e.g. ConnectionReset, message "connection lost") and then the handler task stops, so you get the same kind of notification as when a WebSocket connection is lost. You can also close the connection yourself by calling disconnect(); the same error behavior applies (e.g. one Err(...) to the callback, then the handler exits). send_message can also return an I/O error if the connection is already down. No configuration or code change is needed; this is under the hood.
Local wire format (message framing)
For local connections, the wire format is length-prefixed frames so that one flush sends one message and read returns one message at a time (same semantics as WebSocket). Each frame is: 4-byte big-endian unsigned length (u32), then exactly that many bytes of payload. Messages larger than 4 MiB are rejected with an I/O error. Custom peers (e.g. a server that accepts the raw stream) must use the same frame format to interoperate.
Socket errors
socket_init returns Result<Socket, SocketError>:
SocketError::Io(e)— I/O failure (e.g. connection refused, pipe not found).SocketError::Ws(e)— WebSocket handshake or protocol error.SocketError::UnsupportedCombination(target, os)— That (target, os) pair is not supported on this platform (e.g. local + Linux when building on Windows).SocketError::Detection(e)— Environment variable detection failed (osortargetunset or invalid); only when usingsocket_init(endpoint)with a non-URL endpoint.SocketError::RecipientAckTimeout— Local transport: the recipient did not signal "data acked" within 5 seconds after the sender signaled "data ready".
Once connected, send_message can return an I/O error when the connection is lost, or RecipientAckTimeout if the recipient never acknowledges; message_handler receives one Err(...) before the handler task exits, for any transport.
Minimal end-to-end example
use ;
use mpsc;
async
Language bindings
| Binding | Location | Requirements |
|---|---|---|
| Node/TS | wrappers/ts | Node 18+, Rust (build addon) |
| Python | wrappers/python | Python 3.9+, build ipcez-ffi cdylib |
| C# | wrappers/csharp | .NET 8, build ipcez-ffi cdylib |
Build the C ABI library for Python and C# from the repo root: cargo build -p ipcez-ffi [--release]. Build the Node addon for TS: cargo build -p ipcez-node [--release]. See each wrapper’s README for install and usage.
Build and test
Use --test-threads=1 so env-dependent tests do not race.
On Windows you can build and test everything (Rust, C#, Node addon, optional Python smoke) with:
build-and-test.bat
API documentation
Generate and open the crate docs locally:
License
MIT OR Apache-2.0