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}