[][src]Crate conec

COordinated NEtwork Channels: a network abstraction for communication among many Clients, facilitated by one Coordinator.

Clients are assumed to know (e.g., by configuration or service discovery) the hostname and port number of Coordinator. Coordinator is assumed to have a TLS certificate for this hostname issued by a CA that Clients trust.

The basic abstraction is a channel, which connects two entities (Client or Coordinator). A channel comprises one bi-directional control stream and zero or more unidirectional data streams. Every Client shares a channel with Coordinator: at startup, Client connects to Coordinator.

A data stream accepts a sequence of messages from its writer. The data stream's reader receives these messages in order. The stream handles all message framing: a read yields a full message or nothing. There is no support for out-of-order reads; use multiple data streams instead.

In this version of conec, the only supported data streams are proxied streams: Client sends data to Coordinator, who forwards to another Client. (In a future version, Coordinator will assist Clients in constructing Client-to-Client channels, including NAT traversal.)

Quickstart

A conec instance requires a Coordinator with a TLS certificate for its hostname and an IP address that Clients can reach. It is possible to use a self-signed certificate (generated, say, by rcgen) as long as the Clients trust it; see below.

Coordinator

To start a Coordinator, first build a CoordConfig. For example,

This example is not tested
let mut coord_cfg = CoordConfig::new(cert_path, key_path).unwrap();
coord_cfg.enable_stateless_retry();
coord_cfg.set_port(1337);

Next, pass this configuration to the Coord constructor, which returns a future that, when forced, starts up the Coordinator.

This example is not tested
let coord = Coord::new(coord_cfg).await.unwrap();

The Coord constructor launches driver threads in the background. These threads will run until the Coord struct is dropped and all clients have disconnected.

Client

To start a Client, first build a ClientConfig. For example,

let mut client_cfg =
    ClientConfig::new("itme".to_string(), "coord.conec.example.com".to_string());
client_cfg.set_port(1337);

Next, pass this configuration to the Client constructor, which is a future that returns the Client plus an IncomingStreams object when forced:

This example is not tested
let (client, istreams) = Client::new(client_cfg).await.unwrap();

Streams

Once your Client has connected to its Coordinator, it can set up data streams with other Clients and send data on them:

This example is not tested
let to_you = client
    .new_stream("ityou".to_string(), 0)
    .unwrap()
    .await
    .unwrap();
to_you.send(Bytes::from("hi there")).await.unwrap();

The receiving client first accepts the stream and then reads data from it:

This example is not tested
let (peer, strmid, mut from_me) = istreams
    .next()
    .await
    .unwrap()
    .await
    .unwrap();
println!("Got new stream with id {} from peer {}", strmid, peer);
let rec = from_me
    .try_next()
    .await?
    .unwrap();

Re-exports

pub use client::Client;
pub use coord::Coord;

Modules

client

This module defines the Client entity and associated functionality.

coord

This module defines the Coordinator entity and associated functionality.

Structs

ClientConfig

Client configuration struct

CoordConfig

Coordinator configuration struct

Type Definitions

InStream

Receiving end of a data stream: a Stream of BytesMut.

OutStream

Sending end of a data stream that accepts Bytes.