summaryrefslogtreecommitdiffstats
path: root/src/swarm/peer/forget.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/swarm/peer/forget.rs')
-rw-r--r--src/swarm/peer/forget.rs40
1 files changed, 38 insertions, 2 deletions
diff --git a/src/swarm/peer/forget.rs b/src/swarm/peer/forget.rs
index 624ca97..df09c3c 100644
--- a/src/swarm/peer/forget.rs
+++ b/src/swarm/peer/forget.rs
@@ -1,5 +1,8 @@
//! Swarm-wide forget records (`_continuum/forgotten/<pk>`): a peer forgotten on one
-//! node is forgotten by all; a forgotten node that is alive cancels its record.
+//! node is forgotten by all; a forgotten node that is alive cancels its record. And
+//! locally, strangers that went silent.
+
+use std::time::Duration;
use automerge::AutoCommit;
use tokio::time::Instant;
@@ -7,7 +10,7 @@ use tracing::{info, warn};
use crate::document::meta;
use crate::document::store::{self, StoreError};
-use crate::state::AppState;
+use crate::state::{AppState, Standing};
fn forgotten_dir() -> Vec<String> {
meta::path(&[meta::FORGOTTEN])
@@ -77,3 +80,36 @@ pub(super) async fn apply_forget_records(state: &AppState) {
})
.await;
}
+
+/// How long a peer that never became a member is kept once nothing more is heard from
+/// it: one listed to us that never answered, or one that keeps failing the handshake
+/// (another swarm, a wrong key). Anyone can name peers to a node, so without a limit
+/// the map of peers would only grow.
+const STRANGER_KEPT: Duration = Duration::from_secs(24 * 3600);
+
+/// Forgets peers that never became members and were silent for `STRANGER_KEPT`. Only
+/// here, not swarm-wide; one that comes back is a stranger again.
+pub(super) async fn forget_strangers(state: &AppState) {
+ let now = Instant::now();
+ let mut strangers = Vec::new();
+ for (peer, peer_state) in state.peers_snapshot().await {
+ let peer_state = peer_state.lock().await;
+ let quiet_since = peer_state.last_seen.unwrap_or(peer_state.added_at);
+ if !matches!(peer_state.standing, Standing::Member { .. })
+ && now.saturating_duration_since(quiet_since) >= STRANGER_KEPT
+ {
+ strangers.push(peer);
+ }
+ }
+ if strangers.is_empty() {
+ return;
+ }
+ let mut peer_states = state.peer_states.write().await;
+ for peer in &strangers {
+ peer_states.remove(peer);
+ }
+ info!(
+ forgotten = strangers.len(),
+ "Forgot peers that never became members and were silent for a day"
+ );
+}