Drive events
Choose between poll, next_event, and focused waits without losing unrelated application events.
minip2p remains caller-driven at every layer. The application chooses when to poll, how long to wait, and which event queue to consume. Read where events go first. If you are working with custom streams, also read Register a protocol.
Pick a driving method
| Method | Behavior | Good fit |
|---|---|---|
poll() |
Performs one non-blocking drive and returns all currently available application events. | Existing game, UI, or reactor loops |
next_event(deadline) |
Drives until one ordinary application event or the deadline. | Simple synchronous command loops |
next_wake(deadline) |
Drives until an application event, optional-capability progress, interruption, or the deadline. | One loop handling ordinary and capability-specific events |
wait_peer_ready |
Drives until one peer completes Identify. | Connection setup |
wait_ping_rtt |
Drives until one peer’s Ping finishes. | Health checks and measurements |
| Feature-focused waits | Drive until a NAT, pubsub, signed-discovery, or mDNS result. | Feature-specific workflows |
Deadline forms
Every endpoint wait accepts impl Into<Deadline>:
use std::time::{Duration, Instant};
use minip2p::Deadline;
let relative = Duration::from_secs(5);
let absolute = Instant::now() + Duration::from_secs(5);
let forever = Deadline::NEVER;
An expired deadline still permits the endpoint to inspect events that are already synchronously available, but it will not sleep or poll repeatedly past the deadline.
Build a straightforward event loop
use minip2p::{Deadline, Endpoint, Event};
fn run(mut node: Endpoint) -> Result<(), minip2p::Error> {
while let Some(event) = node.next_event(Deadline::NEVER)? {
match event {
Event::PeerReady { peer_id, .. } => {
println!("ready={peer_id}");
}
Event::Error(error) => {
eprintln!("runtime error: {error:?}");
}
_ => {}
}
}
Ok(())
}
Synchronous method failures are returned as minip2p::Error. Non-fatal
problems that occur later while driving appear as Event::Error or a
feature-specific failure event.
Focused waits preserve other events
Suppose wait_path is waiting for a NAT result while an application stream
receives data. The stream event is retained and becomes available through a
later next_event; it is not discarded by the NAT wait.
That retained backlog is bounded by RUN_UNTIL_SKIP_LIMIT (currently 1024
events). If a focused wait cannot find its result while unrelated events keep
arriving, it returns:
minip2p::Error::EventBacklogExceeded { limit: RUN_UNTIL_SKIP_LIMIT }
Drain ordinary application events with next_event or poll, handle the
high-volume source, and then retry the focused wait.
Stream and connection shutdown
- Call
close_stream_writeafter the final byte for a graceful half-close. - Call
reset_streamwhen the peer should observe abrupt termination and the application still wants terminal events. - Call
abandon_streamwhen no matching buffered or future events should be delivered. - Call
disconnectto close the active peer connection.
Endpoint does not run a background shutdown sequence after it is dropped.
Drive any graceful application-level close exchanges before leaving scope, then
call endpoint.close()?. close consumes the endpoint, disconnects peers, and
briefly drains the resulting events. Dropping also disconnects, but ignores
errors.
With the mdns feature, endpoint.shutdown() has a narrower meaning: it sends
mDNS goodbyes and stops mDNS while leaving QUIC and TCP usable.
Wait for every event family
next_event waits for ordinary endpoint events. Use next_wake when one loop
also needs prompt access to NAT, pubsub, discovery, or relay-server events:
use minip2p::{Deadline, EndpointWake};
loop {
match node.next_wake(Deadline::NEVER)? {
EndpointWake::Event(event) => handle_event(event),
EndpointWake::DriverProgress => {
for event in node.take_pubsub_events() {
handle_pubsub_event(event);
}
}
EndpointWake::Deadline | EndpointWake::Interrupted => {}
}
}
DriverProgress remains ready while any enabled capability queue contains
events. Drain every enabled queue before calling next_wake again. Leaving one
non-empty causes the next call to return immediately.
See Rust troubleshooting for common event symptoms and responses.