Remote channels
MPSC, oneshot, watch and broadcast, with the API you already know from Tokio. They all share one transport and messages are sent in chunks, so a big blob on one channel does not stall the others.
Remote multiplexed objects and channels for Rust.
Channels are how Rust programs talk between tasks. Remoc lets them talk between machines the same way. Send a channel to the other side like any other value and it is connected, inside the one link you already have. That link can be TCP, TLS, a WebSocket, a pipe or a serial line. On top of the channels you also get remote function calls, RPC on traits and observable collections.
$ cargo add remoc
MPSC, oneshot, watch and broadcast, with the API you already know from Tokio. They all share one transport and messages are sent in chunks, so a big blob on one channel does not stall the others.
Put a sender into a struct, an enum or another channel and send it away. The new channel is set up for you inside the connection that is already open. No extra port to allocate, no service registry, no name lookup.
Write a trait, put #[rtc::remote] on it and you get a client and a server
implementation. Arguments and return values may contain channels, so a method can hand
back a stream of updates instead of a single value.
Send a closure over and let the other side call it. The arguments travel one way, the result comes back.
Hash maps, b-tree maps, vectors and sets that publish what happens to them. A subscriber first gets a snapshot and then every change as it occurs.
Locks and read/write locks that also work when the other party is on a different machine, plus values that are only fetched once somebody actually looks at them.
Remoc does no networking. Give it an AsyncRead and AsyncWrite
pair, or a Sink and Stream of packets, and you are connected.
There are worked examples for TCP, TLS, WebSockets, a child process over pipes and
links that survive a broken connection.
Postbag, Bincode, CBOR, JSON, MessagePack or Postcard, chosen per connection. Pick a self-describing one and old and new versions of your software keep understanding each other.
Not a line of unsafe, built on Tokio. It also compiles for
wasm32-unknown-unknown and WASI, so a browser tab can be one end of
the connection.
The client wants the server to count for it. It creates a channel, puts the sender into the request and reads the numbers from the receiver. Nothing else has to be arranged, both channels run through the single TCP connection that was opened at the start.
use remoc::prelude::*;
#[derive(Serialize, Deserialize)]
struct CountReq {
up_to: u32,
// A sender, on its way to the peer.
seq_tx: rch::mpsc::Sender<u32>,
}
let (seq_tx, mut seq_rx) = rch::mpsc::channel(1);
tx.send(CountReq { up_to: 4, seq_tx }).await?;
// The channel is live now, nothing to set up.
while let Some(i) = seq_rx.recv().await? {
println!("{i}");
}
while let Some(req) = rx.recv().await? {
for i in 0..req.up_to {
req.seq_tx.send(i).await?;
}
}
#[rtc::remote]
trait Counter {
async fn value(&self)
-> Result<u32, rtc::CallError>;
async fn watch(&mut self)
-> Result<rch::watch::Receiver<u32>, rtc::CallError>;
}