Skip to main content

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;