karyon_p2p/protocol/mod.rs
1mod peer_conn;
2
3use std::{
4 ops::{BitOr, BitOrAssign},
5 sync::Arc,
6};
7
8use async_trait::async_trait;
9
10use karyon_eventemitter::EventValue;
11
12use crate::{version::Version, Result};
13
14pub use peer_conn::PeerConn;
15
16pub type ProtocolID = String;
17
18/// Protocol event used internally by karyon. User code reads
19/// messages via `PeerConn::recv` which yields `Vec<u8>` directly and
20/// surfaces shutdown as `Err(PeerShutdown)`.
21#[derive(Debug, Clone, EventValue)]
22pub enum ProtocolEvent {
23 /// Message event, contains a vector of bytes.
24 Message(Vec<u8>),
25 /// Shutdown event signals the protocol to gracefully shut down.
26 Shutdown,
27}
28
29/// Bit flags describing how a protocol takes part in handshake and
30/// discovery. Combine with `|`. `empty()` means the protocol is
31/// negotiated but neither required nor advertised.
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct ProtocolFlags(u32);
34
35impl ProtocolFlags {
36 /// Peers must speak this protocol. Handshake fails if absent and
37 /// discovery filters out peers that do not advertise it.
38 pub const REQUIRED: Self = Self(1 << 0);
39 /// Advertised so discovery prefers peers that also have it, but
40 /// peers without it are still accepted. The default.
41 pub const PREFERRED: Self = Self(1 << 1);
42 /// First bit free for user-defined meaning. Bits below are
43 /// reserved by karyon. Kademlia advertises items carrying only
44 /// user bits without letting them affect peer selection; custom
45 /// `Discovery` impls may give them any meaning.
46 pub const USER: Self = Self(1 << 16);
47
48 /// No flags set.
49 pub const fn empty() -> Self {
50 Self(0)
51 }
52
53 /// Raw bit pattern.
54 pub const fn bits(self) -> u32 {
55 self.0
56 }
57
58 /// True if every bit in `other` is set in `self`.
59 pub const fn contains(self, other: Self) -> bool {
60 self.0 & other.0 == other.0
61 }
62}
63
64impl From<u32> for ProtocolFlags {
65 fn from(bits: u32) -> Self {
66 Self(bits)
67 }
68}
69
70impl BitOr for ProtocolFlags {
71 type Output = Self;
72
73 fn bitor(self, rhs: Self) -> Self {
74 Self(self.0 | rhs.0)
75 }
76}
77
78impl BitOrAssign for ProtocolFlags {
79 fn bitor_assign(&mut self, rhs: Self) {
80 self.0 |= rhs.0;
81 }
82}
83
84/// Per-protocol metadata stored in the peer pool.
85#[derive(Clone, Debug)]
86pub struct ProtocolMeta {
87 pub version: Version,
88 pub flags: ProtocolFlags,
89}
90
91/// The Protocol trait defines the interface for core protocols
92/// and custom protocols.
93///
94/// # Example
95/// ```no_run
96/// use std::sync::Arc;
97///
98/// use async_trait::async_trait;
99///
100/// use karyon_core::async_runtime::global_executor;
101/// use karyon_p2p::{
102/// protocol::{PeerConn, Protocol, ProtocolID},
103/// Node, Config, Version, Error,
104/// keypair::{KeyPair, KeyPairType},
105/// };
106///
107/// pub struct NewProtocol {
108/// peer: PeerConn,
109/// }
110///
111/// impl NewProtocol {
112/// fn new(peer: PeerConn) -> Self {
113/// Self { peer }
114/// }
115/// }
116///
117/// #[async_trait]
118/// impl Protocol for NewProtocol {
119/// async fn start(self: Arc<Self>) -> Result<(), Error> {
120/// loop {
121/// let bytes = self.peer.recv().await?;
122/// println!("{:?}", bytes);
123/// }
124/// }
125///
126/// fn version() -> Result<Version, Error> {
127/// "0.2.0, >0.1.0".parse()
128/// }
129///
130/// fn id() -> ProtocolID {
131/// "NEWPROTOCOLID".into()
132/// }
133/// }
134///
135/// async {
136/// let key_pair = KeyPair::generate(&KeyPairType::Ed25519);
137/// let node = Node::new(&key_pair, Config::default(), global_executor());
138/// node.attach_protocol(NewProtocol::new).await.unwrap();
139/// };
140/// ```
141#[async_trait]
142pub trait Protocol: Send + Sync {
143 /// Drive the protocol to completion. Use `self.peer.recv()` etc.
144 async fn start(self: Arc<Self>) -> Result<()>;
145
146 /// Returns the version of the protocol.
147 fn version() -> Result<Version>
148 where
149 Self: Sized;
150
151 /// Returns the unique ProtocolID associated with the protocol.
152 fn id() -> ProtocolID
153 where
154 Self: Sized;
155
156 /// How this protocol takes part in handshake and discovery.
157 /// Defaults to `PREFERRED` -- override with `REQUIRED` for
158 /// protocols needed for any meaningful interaction (e.g. PING).
159 fn flags() -> ProtocolFlags
160 where
161 Self: Sized,
162 {
163 ProtocolFlags::PREFERRED
164 }
165}
166
167/// Boxed protocol constructor stored in the peer pool. Built by
168/// `Node::attach_protocol` from the user's `Fn(PeerConn) -> P` closure.
169/// karyon calls it once per connected peer with a typed `PeerConn`
170/// scoped to this protocol.
171pub type ProtocolConstructor = dyn Fn(PeerConn) -> Arc<dyn Protocol> + Send + Sync;