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;