pub struct P2PNode { /* private fields */ }Expand description
Main P2P network node that manages connections, routing, and communication
This struct represents a complete P2P network participant that can:
- Connect to other peers via QUIC transport
- Participate in distributed hash table (DHT) operations
- Send and receive messages through various protocols
- Handle network events and peer lifecycle
Transport concerns (connections, messaging, events) are delegated to
TransportHandle.
Implementations§
Source§impl P2PNode
impl P2PNode
Sourcepub async fn new(config: NodeConfig) -> Result<Self, P2PError>
pub async fn new(config: NodeConfig) -> Result<Self, P2PError>
Create a new P2P node with the given configuration
Sourcepub fn transport(&self) -> &Arc<TransportHandle>
pub fn transport(&self) -> &Arc<TransportHandle>
Get the transport handle for sharing with other components.
pub fn local_addr(&self) -> Option<MultiAddr>
Sourcepub fn is_bootstrapped(&self) -> bool
pub fn is_bootstrapped(&self) -> bool
Check if the node has completed the initial bootstrap process
Returns true if the node has successfully connected to at least one
bootstrap peer and performed peer discovery (FIND_NODE).
Sourcepub async fn re_bootstrap(&self) -> Result<(), P2PError>
pub async fn re_bootstrap(&self) -> Result<(), P2PError>
Manually trigger re-bootstrap (useful for recovery or network rejoin)
This clears the bootstrapped state and attempts to reconnect to bootstrap peers and discover new peers.
Sourcepub fn trust_engine(&self) -> Arc<TrustEngine>
pub fn trust_engine(&self) -> Arc<TrustEngine>
Get the trust engine for advanced use cases
Sourcepub async fn report_trust_event(&self, peer_id: &PeerId, event: TrustEvent)
pub async fn report_trust_event(&self, peer_id: &PeerId, event: TrustEvent)
Report a trust event for a peer.
Records a network-observable outcome (connection success/failure)
that the DHT layer did not record automatically. See TrustEvent
for the supported variants.
§Example
use saorsa_core::adaptive::TrustEvent;
node.report_trust_event(&peer_id, TrustEvent::SuccessfulResponse).await;
node.report_trust_event(&peer_id, TrustEvent::ConnectionFailed).await;Sourcepub fn peer_trust(&self, peer_id: &PeerId) -> f64
pub fn peer_trust(&self, peer_id: &PeerId) -> f64
Get the current trust score for a peer (0.0 to 1.0).
Returns 0.5 (neutral) for unknown peers.
Sourcepub fn adaptive_dht(&self) -> &AdaptiveDHT
pub fn adaptive_dht(&self) -> &AdaptiveDHT
Get the AdaptiveDHT component for direct access
Sourcepub async fn send_request(
&self,
peer_id: &PeerId,
protocol: &str,
data: Vec<u8>,
timeout: Duration,
) -> Result<PeerResponse, P2PError>
pub async fn send_request( &self, peer_id: &PeerId, protocol: &str, data: Vec<u8>, timeout: Duration, ) -> Result<PeerResponse, P2PError>
Send a request to a peer and wait for a response with automatic trust reporting.
Unlike fire-and-forget send_message(), this method:
- Wraps the payload in a
RequestResponseEnvelopewith a unique message ID - Sends it on the
/rr/<protocol>protocol prefix - Waits for a matching response (or timeout)
- Automatically reports success or failure to the trust engine
The remote peer’s handler should call send_response() with the
incoming message ID to route the response back.
§Arguments
peer_id- Target peerprotocol- Application protocol name (e.g."peer_info")data- Request payload bytestimeout- Maximum time to wait for a response
§Returns
A [PeerResponse] on success, or an error on timeout / connection failure.
§Example
let response = node.send_request(&peer_id, "peer_info", request_data, Duration::from_secs(10)).await?;
println!("Got {} bytes from {}", response.data.len(), response.peer_id);pub async fn send_response( &self, peer_id: &PeerId, protocol: &str, message_id: &str, data: Vec<u8>, ) -> Result<(), P2PError>
pub fn parse_request_envelope(data: &[u8]) -> Option<(String, bool, Vec<u8>)>
pub async fn subscribe(&self, topic: &str) -> Result<(), P2PError>
pub async fn publish(&self, topic: &str, data: &[u8]) -> Result<(), P2PError>
Sourcepub fn config(&self) -> &NodeConfig
pub fn config(&self) -> &NodeConfig
Get the node configuration
Sourcepub fn is_running(&self) -> bool
pub fn is_running(&self) -> bool
Check if the node is running
Sourcepub async fn listen_addrs(&self) -> Vec<MultiAddr>
pub async fn listen_addrs(&self) -> Vec<MultiAddr>
Get the current listen addresses
Sourcepub async fn connected_peers(&self) -> Vec<PeerId>
pub async fn connected_peers(&self) -> Vec<PeerId>
Get connected peers
Sourcepub async fn peer_count(&self) -> usize
pub async fn peer_count(&self) -> usize
Get peer count
Sourcepub async fn is_peer_connected(&self, peer_id: &PeerId) -> bool
pub async fn is_peer_connected(&self, peer_id: &PeerId) -> bool
Check if an authenticated peer is connected (has at least one active channel).
Sourcepub async fn connect_peer(
&self,
address: &MultiAddr,
) -> Result<String, P2PError>
pub async fn connect_peer( &self, address: &MultiAddr, ) -> Result<String, P2PError>
Connect to a peer, returning the transport-level channel ID.
The returned channel ID is not the app-level PeerId. To obtain
the authenticated peer identity, call
wait_for_peer_identity with the
returned channel ID.
Sourcepub async fn wait_for_peer_identity(
&self,
channel_id: &str,
timeout: Duration,
) -> Result<PeerId, P2PError>
pub async fn wait_for_peer_identity( &self, channel_id: &str, timeout: Duration, ) -> Result<PeerId, P2PError>
Wait for the identity exchange on channel_id to complete, returning
the authenticated PeerId.
Use this after connect_peer to bridge the gap
between the transport-level channel ID and the app-level peer identity
required by send_message.
Sourcepub async fn disconnect_peer(&self, peer_id: &PeerId) -> Result<(), P2PError>
pub async fn disconnect_peer(&self, peer_id: &PeerId) -> Result<(), P2PError>
Disconnect from a peer
Sourcepub async fn send_message(
&self,
peer_id: &PeerId,
protocol: &str,
data: Vec<u8>,
addrs: &[MultiAddr],
) -> Result<(), P2PError>
pub async fn send_message( &self, peer_id: &PeerId, protocol: &str, data: Vec<u8>, addrs: &[MultiAddr], ) -> Result<(), P2PError>
Send a message to an authenticated peer, reconnecting on demand.
Tries the existing connection first. If the send fails (stale QUIC session, peer not found, etc.), resolves a dial address from:
- Caller-provided
addrs(highest priority) - Addresses cached in the transport layer (snapshotted before the send attempt, since stale-channel cleanup removes them)
- DHT routing table
Then dials, waits for identity exchange, and retries the send exactly once on the fresh connection. Concurrent reconnects to the same peer are serialised so only one dial is attempted at a time.
Source§impl P2PNode
impl P2PNode
Sourcepub fn subscribe_events(&self) -> Receiver<P2PEvent>
pub fn subscribe_events(&self) -> Receiver<P2PEvent>
Subscribe to network events
Sourcepub async fn health_check(&self) -> Result<(), P2PError>
pub async fn health_check(&self) -> Result<(), P2PError>
Check system health
Sourcepub fn dht_manager(&self) -> &Arc<DhtNetworkManager>
pub fn dht_manager(&self) -> &Arc<DhtNetworkManager>
Get the attached DHT manager.
Sourcepub async fn add_discovered_peer(
&self,
_peer_id: PeerId,
addresses: Vec<MultiAddr>,
) -> Result<(), P2PError>
pub async fn add_discovered_peer( &self, _peer_id: PeerId, addresses: Vec<MultiAddr>, ) -> Result<(), P2PError>
Add a discovered peer to the bootstrap cache
Sourcepub async fn update_peer_metrics(
&self,
addr: &MultiAddr,
success: bool,
latency_ms: Option<u64>,
_error: Option<String>,
) -> Result<(), P2PError>
pub async fn update_peer_metrics( &self, addr: &MultiAddr, success: bool, latency_ms: Option<u64>, _error: Option<String>, ) -> Result<(), P2PError>
Update connection metrics for a peer in the bootstrap cache
Sourcepub async fn get_bootstrap_cache_stats(
&self,
) -> Result<Option<BootstrapStats>, P2PError>
pub async fn get_bootstrap_cache_stats( &self, ) -> Result<Option<BootstrapStats>, P2PError>
Get bootstrap cache statistics
Sourcepub async fn cached_peer_count(&self) -> usize
pub async fn cached_peer_count(&self) -> usize
Get the number of cached bootstrap peers