Skip to main content

karyon_p2p/protocol/
mod.rs

1mod peer_conn;
2
3use std::sync::Arc;
4
5use async_trait::async_trait;
6
7use karyon_eventemitter::EventValue;
8
9use crate::{version::Version, Result};
10
11pub use peer_conn::PeerConn;
12
13pub type ProtocolID = String;
14
15/// Protocol event used internally by karyon. User code reads
16/// messages via `PeerConn::recv` which yields `Vec<u8>` directly and
17/// surfaces shutdown as `Err(PeerShutdown)`.
18#[derive(Debug, Clone, EventValue)]
19pub enum ProtocolEvent {
20    /// Message event, contains a vector of bytes.
21    Message(Vec<u8>),
22    /// Shutdown event signals the protocol to gracefully shut down.
23    Shutdown,
24}
25
26/// Whether a protocol is required for handshake / discovery to consider
27/// a peer compatible.
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub enum ProtocolKind {
30    /// Peers must speak this protocol. Handshake fails if absent.
31    /// Discovery filters out peers whose bloom doesn't cover it.
32    Mandatory,
33    /// Nice-to-have. Discovery prefers peers with overlap but accepts
34    /// peers without it. The default for app protocols.
35    Optional,
36}
37
38/// Per-protocol metadata stored in the peer pool.
39#[derive(Clone, Debug)]
40pub struct ProtocolMeta {
41    pub version: Version,
42    pub kind: ProtocolKind,
43}
44
45/// The Protocol trait defines the interface for core protocols
46/// and custom protocols.
47///
48/// # Example
49/// ```no_run
50/// use std::sync::Arc;
51///
52/// use async_trait::async_trait;
53///
54/// use karyon_core::async_runtime::global_executor;
55/// use karyon_p2p::{
56///     protocol::{PeerConn, Protocol, ProtocolID},
57///     Node, Config, Version, Error,
58///     keypair::{KeyPair, KeyPairType},
59/// };
60///
61/// pub struct NewProtocol {
62///     peer: PeerConn,
63/// }
64///
65/// impl NewProtocol {
66///     fn new(peer: PeerConn) -> Arc<dyn Protocol> {
67///         Arc::new(Self { peer })
68///     }
69/// }
70///
71/// #[async_trait]
72/// impl Protocol for NewProtocol {
73///     async fn start(self: Arc<Self>) -> Result<(), Error> {
74///         loop {
75///             let bytes = self.peer.recv().await?;
76///             println!("{:?}", bytes);
77///         }
78///     }
79///
80///     fn version() -> Result<Version, Error> {
81///         "0.2.0, >0.1.0".parse()
82///     }
83///
84///     fn id() -> ProtocolID {
85///         "NEWPROTOCOLID".into()
86///     }
87/// }
88///
89/// async {
90///     let key_pair = KeyPair::generate(&KeyPairType::Ed25519);
91///     let node = Node::new(&key_pair, Config::default(), global_executor());
92///     node.attach_protocol::<NewProtocol>(|peer| Ok(NewProtocol::new(peer))).await.unwrap();
93/// };
94/// ```
95#[async_trait]
96pub trait Protocol: Send + Sync {
97    /// Drive the protocol to completion. Use `self.peer.recv()` etc.
98    async fn start(self: Arc<Self>) -> Result<()>;
99
100    /// Returns the version of the protocol.
101    fn version() -> Result<Version>
102    where
103        Self: Sized;
104
105    /// Returns the unique ProtocolID associated with the protocol.
106    fn id() -> ProtocolID
107    where
108        Self: Sized;
109
110    /// Whether peers must speak this protocol or it's optional.
111    /// Defaults to `Optional` -- override for protocols required for
112    /// any meaningful interaction (e.g. PING).
113    fn kind() -> ProtocolKind
114    where
115        Self: Sized,
116    {
117        ProtocolKind::Optional
118    }
119}
120
121/// User-supplied constructor handed to `Node::attach_protocol`.
122/// karyon calls it once per connected peer with a typed `PeerConn`
123/// scoped to this protocol. Capture whatever shared state the
124/// protocol needs in the closure.
125pub type ProtocolConstructor = dyn Fn(PeerConn) -> Result<Arc<dyn Protocol>> + Send + Sync;