scatter_net/legacy/peer/methods/
select_peer_group.rs

1use std::time::Duration;
2
3use n0_future::StreamExt;
4use tokio::time::sleep;
5
6use crate::{ErrorCode, Peer, PeerGroup, Terminate};
7
8impl Peer {
9    /// Inserts this [`Peer`] into a [`PeerGroup`], if it isn't in one already.
10    pub async fn select_peer_group(self) -> Result<PeerGroup, PeerSelectPeerGroupError> {
11        sleep(Duration::from_secs(1)).await;
12
13        let mut interaction = self.clone().begin_interaction().await?;
14        let time_start = chrono::Local::now();
15
16        interaction.send_packet(crate::Packet::Ping).await?;
17
18        let pong = interaction.next().await;
19        let time_end = chrono::Local::now();
20
21        if !matches!(pong, Some(Ok(crate::Packet::Pong))) {
22            self.terminate(
23                ErrorCode::PingPongFailed as u8,
24                &"Failed to play ping pong.",
25            );
26
27            eprintln!("Failed to play ping pong with {self}, received {pong:?}.");
28
29            return Err(PeerSelectPeerGroupError::PingPongFailed);
30        }
31
32        let rtt = (time_end - time_start).num_milliseconds().unsigned_abs();
33
34        let mut peer_group: Option<crate::PeerGroup> = None;
35
36        for g in self.net().get_peer_groups() {
37            if g.has_peer(&self) {
38                // self already in a peer_group, we're done here
39                return Ok(g);
40            }
41
42            if !g.is_open() || rtt > g.get_rtt_cap_ms() {
43                // cannot join peer group
44                continue;
45            }
46
47            if let Some(og) = peer_group {
48                if g.get_rtt_cap_ms() < og.get_rtt_cap_ms() {
49                    peer_group = Some(g);
50                } else {
51                    peer_group = Some(og);
52                }
53            } else {
54                peer_group = Some(g);
55            }
56        }
57
58        let node_id = self.node_id();
59
60        peer_group.map_or_else(
61            || {
62                eprintln!("Could not find a suitable PeerGroup for {node_id}");
63
64                Err(PeerSelectPeerGroupError::NoSuitablePeerGroup)
65            },
66            |peer_group| {
67                eprintln!("Peer {node_id} inserted into {peer_group}.");
68
69                peer_group.insert_peer(self);
70
71                Ok(peer_group)
72            },
73        )
74    }
75}
76
77#[derive(thiserror::Error, Debug)]
78pub enum PeerSelectPeerGroupError {
79    #[error(transparent)]
80    InteractionSendPacket(#[from] crate::InteractionSendPacketError),
81    #[error("Could not find a suitable PeerGroup.")]
82    NoSuitablePeerGroup,
83    #[error(transparent)]
84    PeerBeginInteraction(#[from] crate::PeerBeginInteractionError),
85    #[error("Peer did not respond to Packet::Ping with Packet::Pong.")]
86    PingPongFailed,
87}