Crate hypercore_protocol[][src]

Expand description

Hypercore protocol is a streaming, message based protocol

This crate does not include any IO related code, it is up to the user to supply a streaming IO handler that implements the AsyncRead and AsyncWrite traits.

When opening a Hypercore protocol stream on an IO handler, the protocol will perform a Noise handshake to setup a secure and authenticated connection. After that, each side can request any number of channels on the protocol. A channel is opened with a Key, a 32 byte buffer. Channels are only opened if both peers opened a channel for the same key. It is automatically verified that both parties know the key without transmitting the key itself.

On a channel, the predefined messages of the Hypercore protocol can be sent and received. Additionally, Hypercore protocol supports protocol extensions that can be registered both on an individual channel and on the main protocol stream. Extensions are registered with a string name and are only established if both peers register an extension with the same name. Each extension then can be used as a duplex stream. Note that individual messages on an extension stream are enrypted but not authenticated.

The following example opens a TCP server on localhost and connects to that server. Both ends then open a channel with the same key and exchange a message.

use hypercore_protocol::{ProtocolBuilder, Event, Message};
use hypercore_protocol::schema::*;
use async_std::prelude::*;

// Start a tcp server.
let listener = async_std::net::TcpListener::bind("localhost:8000").await.unwrap();
async_std::task::spawn(async move {
    let mut incoming = listener.incoming();
    while let Some(Ok(stream)) = incoming.next().await {
        async_std::task::spawn(async move {
            onconnection(stream, false).await
        });
    }
});

// Connect a client.
let stream = async_std::net::TcpStream::connect("localhost:8000").await.unwrap();
onconnection(stream, true).await;

/// Start Hypercore protocol on a TcpStream.
async fn onconnection (stream: async_std::net::TcpStream, is_initiator: bool) {
    // A peer either is the initiator or a connection or is being connected to.
    let name = if is_initiator { "dialer" } else { "listener" };
    // A key for the channel we want to open. Usually, this is a pre-shared key that both peers
    // know about.
    let key = [3u8; 32];
    // Create the protocol.
    let mut protocol = ProtocolBuilder::new(is_initiator).connect(stream);

    // Iterate over the protocol events. This is required to "drive" the protocol.
    while let Some(Ok(event)) = protocol.next().await {
        eprintln!("{} received event {:?}", name, event);
        match event {
            // The handshake event is emitted after the protocol is fully established.
            Event::Handshake(_remote_key) => {
                protocol.open(key.clone()).await;
            },
            // A Channel event is emitted for each established channel.
            Event::Channel(mut channel) => {
                // A Channel can be sent to other tasks.
                async_std::task::spawn(async move {
                    // A Channel can both send messages and is a stream of incoming messages.
                    channel.want(Want { start: 0, length: None }).await;
                    while let Some(message) = channel.next().await {
                        eprintln!("{} received message: {:?}", name, message);
                    }
                });
            },
            _ => {}
        }
    }
}

Modules

The wire messages used by the protocol.

Structs

A protocol channel.

Duplex IO stream from reader and writer halves.

A protocol extension.

Options for a Protocol instance.

A Protocol stream.

Build a Protocol instance with options.

Enums

A protocol event.

A protocol message.

Functions

Calculate the discovery key of a key.

Type Definitions

Discovery key (32 bytes).

Key (32 bytes).