peerlink/
lib.rs

1//! # Peer-to-peer networking reactor
2//!
3//! Peerlink is a low-level building block for P2P applications. It uses a nonblocking reactor to
4//! accept inbound connections, make outbound connections, do message streaming and reassembly,
5//! track peers and perform other low-level operations. It entirely abstracts away menial
6//! networking plumbing such as managing TCP sockets and reading bytes off the wire. In other
7//! words, it provides the consumer with a simple interface to talking with other nodes in a P2P
8//! network.
9//!
10//! See the included example for usage.
11
12pub mod connector;
13mod message_stream;
14pub mod reactor;
15
16use std::num::NonZeroUsize;
17
18pub use message_stream::StreamConfig;
19pub use mio::net::TcpStream;
20pub use reactor::{Command, Event, Handle, Reactor};
21
22#[cfg(not(feature = "async"))]
23pub use crossbeam_channel;
24
25#[cfg(feature = "async")]
26pub use async_channel;
27
28/// Configuration parameters for the reactor.
29#[derive(Debug)]
30pub struct Config {
31    /// The list of socket addresses where the reactor listens for inbound connections.
32    pub bind_addr: Vec<std::net::SocketAddr>,
33    /// Configuration parameters for individual peer connections. This allows the fine tuning of
34    /// internal buffer sizes etc. Most consumers won't have to modify the default values.
35    pub stream_config: StreamConfig,
36    /// The size of the shared receive buffer, i.e. the max number of bytes that can be read in one
37    /// receive operation. Setting this too low can cause many reads to happen, whereas too high a
38    /// figure will use up more memory. The default is 1 megabyte.
39    pub receive_buffer_size: usize,
40    /// Whether the reactor should perform backpressure control on the receive side. Setting this
41    /// to `Some(n)` means that the reactor will start blocking on sending events to the consumer
42    /// when the receive channel of size `n` is full and events are not being read. Setting it to
43    /// `None` means that the capacity of the event channel is unbounded and the reactor will send
44    /// events to the consumer as fast as it can, regardless of whether those events are being read
45    /// (at all). The default is no backpressure control (`None`).
46    pub receive_backpressure_control: Option<NonZeroUsize>,
47}
48
49impl Default for Config {
50    fn default() -> Self {
51        Self {
52            bind_addr: Default::default(),
53            stream_config: Default::default(),
54            receive_buffer_size: 1024 * 1024,
55            receive_backpressure_control: None,
56        }
57    }
58}
59
60/// A trait that network messages processed by the reactor must implement.
61pub trait Message: std::fmt::Debug + Sized + Send + Sync + 'static {
62    /// Encodes a message into a writer. This is an in-memory writer that never panics so there is
63    /// no need to handle the error path.
64    ///
65    /// Returns the number of encoded bytes.
66    fn encode(&self, dest: &mut impl std::io::Write) -> usize;
67
68    /// Provides access to the underlying read buffer. The buffer may contain any number of
69    /// messages, including no messages at all or only a partial message. If there are enough bytes
70    /// available to decode a message, the function must return an `Ok` with the decoded message
71    /// and the number of bytes it consumed.
72    ///
73    /// If there is not enough data to decode a message (i.e. it is available only partially),
74    /// `Err(DecodeError::NotEnoughData)` must be returned. That signals that the read should be
75    /// retried. If the message cannot be decoded at all, or exceeds size limits or otherwise
76    /// represents junk data, `Err(DecodeError::MalformedMessage)` must be returned. Such peers are
77    /// disconnected as protocol violators.
78    fn decode(buffer: &[u8]) -> Result<(Self, usize), DecodeError>;
79}
80
81/// Possible reasons why a message could not be decoded at a particular time.
82#[derive(Debug, PartialEq, Eq)]
83pub enum DecodeError {
84    /// There is not enough data available to reconstruct a message. This does not indicate an
85    /// irrecoverable problem, it just means that not enough data has been taken of the wire yet
86    /// and that the operation should be retried once more data comes in.
87    NotEnoughData,
88    /// The message is malformed in some way. Once this is encountered, the peer that sent it
89    /// is disconnected.
90    MalformedMessage,
91}
92
93/// Unique peer identifier. These are unique for the lifetime of the process and strictly
94/// incrementing for each new connection. Even if the same peer (in terms of socket address)
95/// connects multiple times, a new `PeerId` instance will be issued for each connection.
96#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq, PartialOrd, Ord)]
97pub struct PeerId(pub u64);
98
99impl std::fmt::Display for PeerId {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        write!(f, "{}", self.0)
102    }
103}