pub struct Node { /* private fields */ }Expand description
Zero-configuration P2P node
This is the primary API for ant-quic. Create a node with zero configuration and it will automatically handle NAT traversal, post-quantum cryptography, and peer discovery.
§Symmetric P2P
All nodes are equal - every node can:
- Connect to other nodes
- Accept incoming connections
- Act as coordinator for NAT traversal
- Act as relay for peers behind restrictive NATs
§Post-Quantum Security
v0.2: Every connection uses pure post-quantum cryptography:
- Key Exchange: ML-KEM-768 (FIPS 203)
- Authentication: ML-DSA-65 (FIPS 204)
- Ed25519 is used ONLY for the 32-byte PeerId compact identifier
There is no classical crypto fallback - security is quantum-resistant by default.
§Example
use ant_quic::Node;
// Zero configuration
let node = Node::new().await?;
// Or with known peers
let node = Node::with_peers(vec!["quic.saorsalabs.com:9000".parse()?]).await?;
// Or with persistent identity
let keypair = load_keypair()?;
let node = Node::with_keypair(keypair).await?;Implementations§
Source§impl Node
impl Node
Sourcepub async fn bind(addr: SocketAddr) -> Result<Self, NodeError>
pub async fn bind(addr: SocketAddr) -> Result<Self, NodeError>
Sourcepub async fn with_peers(peers: Vec<SocketAddr>) -> Result<Self, NodeError>
pub async fn with_peers(peers: Vec<SocketAddr>) -> Result<Self, NodeError>
Create a node with known peers
Use this when you have a list of known peers to connect to initially. These can be any nodes in the network - they’ll help with NAT traversal.
§Example
let node = Node::with_peers(vec![
"quic.saorsalabs.com:9000".parse()?,
"peer2.example.com:9000".parse()?,
]).await?;Sourcepub async fn with_keypair(
public_key: MlDsaPublicKey,
secret_key: MlDsaSecretKey,
) -> Result<Self, NodeError>
pub async fn with_keypair( public_key: MlDsaPublicKey, secret_key: MlDsaSecretKey, ) -> Result<Self, NodeError>
Create a node with an existing keypair
Use this for persistent identity across restarts. The peer ID is derived from the public key, so using the same keypair gives you the same peer ID.
§Example
let (public_key, secret_key) = load_keypair_from_file("~/.ant-quic/identity.key")?;
let node = Node::with_keypair(public_key, secret_key).await?;Sourcepub async fn with_config(config: NodeConfig) -> Result<Self, NodeError>
pub async fn with_config(config: NodeConfig) -> Result<Self, NodeError>
Create a node with full configuration
For power users who need specific settings. Most applications
should use Node::new() or one of the convenience methods.
§Example
let config = NodeConfig::builder()
.bind_addr("0.0.0.0:9000".parse()?)
.known_peer("quic.saorsalabs.com:9000".parse()?)
.keypair(load_keypair()?)
.build();
let node = Node::with_config(config).await?;Sourcepub fn peer_id(&self) -> PeerId
pub fn peer_id(&self) -> PeerId
Get this node’s peer ID
The peer ID is derived from the Ed25519 public key and is the unique identifier for this node on the network.
Sourcepub fn local_addr(&self) -> Option<SocketAddr>
pub fn local_addr(&self) -> Option<SocketAddr>
Get the local bind address
Returns None if the endpoint hasn’t bound yet.
Sourcepub fn external_addr(&self) -> Option<SocketAddr>
pub fn external_addr(&self) -> Option<SocketAddr>
Get the observed external address
This is the address as seen by other peers on the network.
Returns None if no external address has been discovered yet.
Sourcepub fn public_key_bytes(&self) -> &[u8] ⓘ
pub fn public_key_bytes(&self) -> &[u8] ⓘ
Get the ML-DSA-65 public key bytes (1952 bytes)
Sourcepub async fn connect_addr(
&self,
addr: SocketAddr,
) -> Result<PeerConnection, NodeError>
pub async fn connect_addr( &self, addr: SocketAddr, ) -> Result<PeerConnection, NodeError>
Sourcepub async fn accept(&self) -> Option<PeerConnection>
pub async fn accept(&self) -> Option<PeerConnection>
Sourcepub async fn add_peer(&self, addr: SocketAddr)
pub async fn add_peer(&self, addr: SocketAddr)
Add a known peer dynamically
Known peers help with NAT traversal and peer discovery. You can add more peers at runtime.
Sourcepub async fn connect_known_peers(&self) -> Result<usize, NodeError>
pub async fn connect_known_peers(&self) -> Result<usize, NodeError>
Connect to all known peers
Returns the number of successful connections.
Sourcepub async fn disconnect(&self, peer_id: &PeerId) -> Result<(), NodeError>
pub async fn disconnect(&self, peer_id: &PeerId) -> Result<(), NodeError>
Disconnect from a peer
Sourcepub async fn connected_peers(&self) -> Vec<PeerConnection>
pub async fn connected_peers(&self) -> Vec<PeerConnection>
Get list of connected peers
Sourcepub async fn is_connected(&self, peer_id: &PeerId) -> bool
pub async fn is_connected(&self, peer_id: &PeerId) -> bool
Check if connected to a peer
Sourcepub async fn send(&self, peer_id: &PeerId, data: &[u8]) -> Result<(), NodeError>
pub async fn send(&self, peer_id: &PeerId, data: &[u8]) -> Result<(), NodeError>
Send data to a peer
Sourcepub async fn recv(
&self,
timeout: Duration,
) -> Result<(PeerId, Vec<u8>), NodeError>
pub async fn recv( &self, timeout: Duration, ) -> Result<(PeerId, Vec<u8>), NodeError>
Receive data from any peer
Sourcepub async fn status(&self) -> NodeStatus
pub async fn status(&self) -> NodeStatus
Get a snapshot of the node’s current status
This provides complete visibility into the node’s state, including NAT type, connectivity, relay status, and performance.
§Example
let status = node.status().await;
println!("NAT type: {}", status.nat_type);
println!("Connected peers: {}", status.connected_peers);
println!("Acting as relay: {}", status.is_relaying);Sourcepub fn subscribe(&self) -> Receiver<NodeEvent>
pub fn subscribe(&self) -> Receiver<NodeEvent>
Subscribe to node events
Returns a receiver for all significant node events including connections, disconnections, NAT detection, and relay activity.
§Example
let mut events = node.subscribe();
tokio::spawn(async move {
while let Ok(event) = events.recv().await {
match event {
NodeEvent::PeerConnected { peer_id, .. } => {
println!("Connected: {:?}", peer_id);
}
_ => {}
}
}
});Sourcepub fn subscribe_raw(&self) -> Receiver<P2pEvent>
pub fn subscribe_raw(&self) -> Receiver<P2pEvent>
Subscribe to raw P2pEvents (for advanced use)
This provides access to the underlying P2pEndpoint events.
Most applications should use subscribe() for NodeEvents.
Sourcepub async fn shutdown(self)
pub async fn shutdown(self)
Gracefully shut down the node
This closes all connections and releases resources.
Sourcepub fn is_running(&self) -> bool
pub fn is_running(&self) -> bool
Check if the node is still running