1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
//! ## Introduction
//!
//! Hypercore protocol is a streaming, message based protocol. This is a rust port of the wire
//! protocol implementation in [the original Javascript version][holepunch-hypercore] aiming
//! for interoperability with LTS version.
//!
//! This crate is built on top of the [hypercore] crate, which defines some structs used here.
//!
//! ## Design
//!
//! 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 followed by libsodium's [crypto_secretstream] 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, including a custom Extension message, of the Hypercore
//! protocol can be sent and received.
//!
//! ## Features
//!
//! ### `sparse` (default)
//!
//! When using disk storage for hypercore, clearing values may create sparse files. On by default.
//!
//! ### `async-std` (default)
//!
//! Use the async-std runtime, on by default. Either this or `tokio` is mandatory.
//!
//! ### `tokio`
//!
//! Use the tokio runtime. Either this or `async_std` is mandatory.
//!
//! ### `wasm-bindgen`
//!
//! Enable for WASM runtime support.
//!
//! ### `cache`
//!
//! Use a moka cache for hypercore's merkle tree nodes to speed-up reading.
//!
//! ## Example
//!
//! 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.
//!
//! ```no_run
//! # async_std::task::block_on(async {
//! 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.send(Message::Want(Want { start: 0, length: 1 })).await;
//! while let Some(message) = channel.next().await {
//! eprintln!("{} received message: {:?}", name, message);
//! }
//! });
//! },
//! _ => {}
//! }
//! }
//! }
//! # })
//! ```
//!
//! Find more examples in the [Github repository][examples].
//!
//! [holepunch-hypercore]: https://github.com/holepunchto/hypercore
//! [datrs-hypercore]: https://github.com/datrs/hypercore
//! [AsyncRead]: futures_lite::AsyncRead
//! [AsyncWrite]: futures_lite::AsyncWrite
//! [examples]: https://github.com/datrs/hypercore-protocol-rs#examples
#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
#![deny(missing_debug_implementations, nonstandard_style)]
#![warn(missing_docs, unreachable_pub)]
mod builder;
mod channels;
mod constants;
mod crypto;
mod duplex;
mod message;
mod protocol;
mod reader;
mod util;
mod writer;
/// The wire messages used by the protocol.
pub mod schema;
pub use builder::Builder as ProtocolBuilder;
pub use channels::Channel;
// Export the needed types for Channel::take_receiver, and Channel::local_sender()
pub use async_channel::{
Receiver as ChannelReceiver, SendError as ChannelSendError, Sender as ChannelSender,
};
pub use duplex::Duplex;
pub use hypercore; // Re-export hypercore
pub use message::Message;
pub use protocol::{DiscoveryKey, Event, Key, Protocol};
pub use util::discovery_key;