Remoc 🦑 — remote multiplexed objects and channels
Remoc makes remote interaction between Rust programs seamless and smooth. Over a single underlying transport, such as TCP or TLS, it provides:
- multiple channels of different types like MPSC, oneshot, watch, etc.,
- remote synchronization primitives,
- calling of remote functions and trait methods on a remote object (RPC),
- remotely observable collections.
Remoc is written in 100% safe Rust, builds upon Tokio, works with any type and data format supported by Serde and does not depend on any particular transport type.
Introduction
A common pattern in Rust programs is to use channels to communicate between threads and async tasks. Setting up a channel is done in a single line and it largely avoids the need for shared state and the associated complexity. Remoc extends this programming model to distributed systems by providing channels that work seamlessly over remote connections.
For that it uses Serde to serialize and deserialize data as it gets transmitted over an underlying transport, which might be a TCP network connection, a WebSocket, UNIX pipe, or even a serial link.
Opening a new channel is straightforward, just send the sender or receiver half of the new channel over an existing channel, like you would do between local threads and tasks. All channels are multiplexed over the same remote connection, with data being transmitted in chunks to avoid one channel blocking another if a large message is transmitted.
Building upon its remote channels, Remoc allows calling of remote functions and closures. Furthermore, a trait can be made remotely callable with automatically generated client and server implementations, resembling a classical remote procedure calling (RPC) model.
Forward and backward compatibility
Distributed systems often require that endpoints running different software versions interact. By utilizing a self-describing data format like JSON for encoding of your data for transport, you can ensure a high level of backward and forward compatibility.
It is always possible to add new fields to enums and struct and utilize the
#[serde(default)]
attribute to provide default values for that field if it
was sent by an older client that has no knowledge of it.
Likewise additional, unknown fields are silently ignored when received,
allowing you to extend the data format without disturbing legacy endpoints.
Check the documentation of the employed data format for details.
Crate features
Most functionality of Remoc is gated by crate features. The following features are available:
serde
enables thecodec
module and implements serialize and deserialize for all configuration and error types.rch
enables remote channels provided by therch
module.rfn
enables remote function calling provided by therfn
module.robj
enables remote object utilities provided by therobj
module.robs
enables remotely observable collections provided by therobs
module.rtc
enables remote trait calling provided by thertc
module.
The meta-feature full
enables all features from above but no codecs.
The following features enable data formats for transmission:
codec-bincode
provides the Bincode format.codec-ciborium
provides the CBOR format.codec-json
provides the JSON format.codec-message-pack
provides the MessagePack format.
The feature default-codec-*
selects the respective codec as default.
At most one of this must be selected and this should only be used by
applications, not libraries.
The feature full-codecs
enables all codecs.
By default all features are enabled and the JSON codec is used as default.
Supported Rust versions
Remoc is built against the latest stable release. The minimum supported Rust version (MSRV) is 1.59.
Example
This is a short example; for a fully worked remote trait calling (RTC) example see the examples directory.
In the following example the server listens on TCP port 9870 and the client connects to it.
Then both ends establish a Remoc connection using Connect::io()
over the TCP connection.
The connection dispatchers are spawned onto new tasks and the client()
and server()
functions
are called with the established base channel.
Then, the client creates a new remote MPSC channel and sends it inside a count request to the
server.
The server receives the count request and counts on the provided channel.
The client receives each counted number over the new channel.
use Ipv4Addr;
use ;
use *;
async
// This would be run on the client.
// It establishes a Remoc connection over TCP to the server.
async
// This would be run on the server.
// It accepts a Remoc connection over TCP from the client.
async
// User-defined data structures needs to implement Serialize
// and Deserialize.
// This would be run on the client.
// It sends a count request to the server and receives each number
// as it is counted over a newly established MPSC channel.
async
// This would be run on the server.
// It receives a count request from the client and sends each number
// as it is counted over the MPSC channel sender provided by the client.
async
Sponsors
Development of Remoc is partially sponsored by ENQT GmbH.
License
Remoc is licensed under the Apache 2.0 license.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Remoc by you, shall be licensed as Apache 2.0, without any additional terms or conditions.