p2p_chat/sync/engine/discovery/
providers.rs

1//! This module contains helper functions for `SyncEngine` related to managing
2//! and ranking mailbox providers.
3use std::collections::HashSet;
4
5use libp2p::PeerId;
6
7use super::super::SyncEngine;
8
9impl SyncEngine {
10    /// Returns a reference to the set of discovered mailbox providers.
11    pub fn get_mailbox_providers(&self) -> &HashSet<PeerId> {
12        &self.discovered_mailboxes
13    }
14
15    /// Returns a ranked list of available mailbox providers.
16    ///
17    /// The ranking is based on performance metrics stored in the `SyncEngine`.
18    pub fn get_available_mailboxes(&self) -> Vec<PeerId> {
19        self.rank_mailboxes(self.discovered_mailboxes.iter().cloned())
20    }
21
22    /// Returns a ranked list of a subset of mailbox providers.
23    ///
24    /// # Arguments
25    ///
26    /// * `providers` - The subset of `PeerId`s to rank.
27    pub fn rank_mailboxes_subset(&self, providers: &HashSet<PeerId>) -> Vec<PeerId> {
28        self.rank_mailboxes(providers.iter().cloned())
29    }
30
31    /// Asynchronously retrieves a list of "emergency" mailboxes.
32    ///
33    /// These are connected peers that are also known mailbox providers.
34    ///
35    /// # Returns
36    ///
37    /// A `Vec` of `PeerId`s representing the emergency mailboxes.
38    pub async fn get_emergency_mailboxes(&self) -> Vec<PeerId> {
39        let Some(network) = &self.network else {
40            return vec![];
41        };
42
43        match network.get_connected_peers().await {
44            Ok(peers) => peers
45                .into_iter()
46                .filter(|peer| self.discovered_mailboxes.contains(peer))
47                .collect(),
48            Err(_) => vec![],
49        }
50    }
51
52    /// Determines if a mailbox should be forgotten due to poor performance.
53    ///
54    /// This is based on consecutive failures or too many failures within a time window.
55    pub(crate) fn should_forget_mailbox(&self, peer_id: PeerId) -> bool {
56        use super::super::performance::{
57            FAILURE_WINDOW_SECONDS, MAX_CONSECUTIVE_FAILURES, MAX_FAILURES_IN_WINDOW,
58        };
59
60        if let Some(perf) = self.mailbox_performance.get(&peer_id) {
61            if perf.consecutive_failures >= MAX_CONSECUTIVE_FAILURES {
62                return true;
63            }
64
65            if let Some(last_failure) = perf.last_failure {
66                let time_since_last_failure = last_failure.elapsed().as_secs();
67                if time_since_last_failure <= FAILURE_WINDOW_SECONDS
68                    && perf.failure_count >= MAX_FAILURES_IN_WINDOW
69                {
70                    return true;
71                }
72            }
73        }
74        false
75    }
76}