scatter_net/legacy/peer/methods/
ping.rs

1use std::time::Duration;
2
3use chrono::TimeDelta;
4use n0_future::StreamExt;
5use tokio::time::timeout;
6
7use crate::Peer;
8
9impl Peer {
10    /// Sends a ping packet to the peer and measures the round-trip time.
11    ///
12    /// # Arguments
13    /// * `timeout_duration` - Maximum time to wait for a pong response
14    ///
15    /// # Returns
16    /// * `Ok(TimeDelta)` - Round-trip time
17    /// * `Err(PeerPingError)` - Various failure modes
18    pub async fn ping(self, timeout_duration: Duration) -> Result<TimeDelta, PeerPingError> {
19        let mut interaction = self.begin_interaction().await?;
20
21        let time_start = chrono::Local::now();
22
23        interaction.send_packet(crate::Packet::Ping).await?;
24
25        let response = match timeout(timeout_duration, interaction.next()).await {
26            Ok(Some(result)) => result?,
27            Ok(None) => Err(PeerPingError::ConnectionClosed)?,
28            Err(_) => Err(PeerPingError::Timeout {
29                timeout_ms: timeout_duration.as_millis().try_into()?,
30            })?,
31        };
32
33        let time_end = chrono::Local::now();
34
35        match response {
36            crate::Packet::Pong => Ok(time_end - time_start),
37            packet => Err(PeerPingError::UnexpectedResponse { received: packet }),
38        }
39    }
40}
41
42#[derive(thiserror::Error, Debug)]
43pub enum PeerPingError {
44    #[error(transparent)]
45    BeginInteraction(#[from] crate::PeerBeginInteractionError),
46    #[error("Connection closed before receiving response")]
47    ConnectionClosed,
48    #[error("Reading packet failed: {0}")]
49    ReadPacket(#[from] crate::InteractionReadPacketError),
50    #[error("Sending packet failed: {0}")]
51    SendPacket(#[from] crate::InteractionSendPacketError),
52    #[error("Ping timed out after {timeout_ms}ms")]
53    Timeout { timeout_ms: u64 },
54    #[error("Expected Pong packet, received {received:?}")]
55    UnexpectedResponse { received: crate::Packet },
56    #[error(transparent)]
57    IntConversion(#[from] std::num::TryFromIntError),
58}