diff options
| author | tv <tv@krebsco.de> | 2026-10-27 01:01:51 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-27 01:01:51 +0100 |
| commit | 5fd686dcd8ddfbdf276c044e5acf03f744e03193 (patch) | |
| tree | a4f04328c8a2de0a50d3af3c9a8a92bfe2b118a2 /src/swarm/members.rs | |
| parent | b90cfd1fde4e1c00d03e44976753d0044b273bda (diff) | |
introduce addresses
Diffstat (limited to 'src/swarm/members.rs')
| -rw-r--r-- | src/swarm/members.rs | 66 |
1 files changed, 60 insertions, 6 deletions
diff --git a/src/swarm/members.rs b/src/swarm/members.rs index cb8a558..c2edd01 100644 --- a/src/swarm/members.rs +++ b/src/swarm/members.rs @@ -10,8 +10,10 @@ //! //! Besides its tier, an entry holds the alias a node gives itself (`--alias`), a name //! for people reading /peers and metrics (not unique and never an identity: the public -//! key stays that), and an `alive` stamp the node renews now and then: the members -//! renewed within `--electorate-window` are the electorate of a remake. +//! key stays that), where it can be reached (`addresses`, as its transport gives them: +//! hints for the others' transports), and an `alive` stamp the node renews now and +//! then: the members renewed within `--electorate-window` are the electorate of a +//! remake. use std::collections::HashMap; use std::time::Duration; @@ -108,6 +110,42 @@ fn set_alias(doc: &mut AutoCommit, pk: &str, alias: Option<&str>) -> Result<(), } } +fn addresses_path(pk: &str) -> Vec<String> { + let mut path = member_path(pk); + path.push("addresses".to_owned()); + path +} + +/// Addresses a member most likely has, at most: one per transport. +const MAX_ADDRESSES: usize = 8; + +/// Where `pk` says it can be reached (at most `MAX_ADDRESSES`); none if its entry +/// doesn't say. +pub(crate) fn addresses(doc: &AutoCommit, pk: &str) -> Vec<String> { + match store::read_path(doc, &addresses_path(pk)) { + Ok(Some(JsonValue::Array(items))) => items + .into_iter() + .filter_map(|item| match item { + JsonValue::String(address) => Some(address), + _ => None, + }) + .take(MAX_ADDRESSES) + .collect(), + _ => Vec::new(), + } +} + +/// Hands every other member's addresses to the transport (`Transport::learn_addresses`): +/// the member list is how a node finds where members it never met are. +pub(crate) fn learn_addresses(state: &AppState, doc: &AutoCommit) { + let me = state.local_id(); + for pk in members(doc) { + if pk != me { + state.transport.learn_addresses(&pk, &addresses(doc, &pk)); + } + } +} + fn alive_path(pk: &str) -> Vec<String> { let mut path = member_path(pk); path.push("alive".to_owned()); @@ -146,15 +184,16 @@ fn alive_renewal(window: Duration) -> Duration { } /// Registers this node if it is ready and its entry is missing, keeps its alias as -/// configured (set, changed or removed after a restart with another `--alias`), and -/// renews its `alive` stamp now and then (see `electorate`). +/// configured (set, changed or removed after a restart with another `--alias`) and its +/// addresses as the transport gives them, and renews its `alive` stamp now and then +/// (see `electorate`). pub(crate) async fn ensure_registered(state: &AppState) { if !state.is_ready().await { return; } let local = state.local_id().to_owned(); let own = member_path(&local); - let (registered, recorded_alias, alive) = { + let (registered, recorded_alias, recorded_addresses, alive) = { let replica = state.doc.read().await; let registered = store::read_path(&replica.doc, &own) .ok() @@ -163,14 +202,17 @@ pub(crate) async fn ensure_registered(state: &AppState) { ( registered, alias(&replica.doc, &local), + addresses(&replica.doc, &local), millis_at(&replica.doc, &alive_path(&local)), ) }; let wanted = state.alias.clone(); + let mut own_addresses = state.transport.local_addresses(); + own_addresses.truncate(MAX_ADDRESSES); let now = state.clock.now_millis().as_u64(); if !registered { - let mut entry = json!({ "since": now, "alive": now }); + let mut entry = json!({ "since": now, "alive": now, "addresses": own_addresses }); if let Some(alias) = &wanted { entry["alias"] = json!(alias); } @@ -199,6 +241,18 @@ pub(crate) async fn ensure_registered(state: &AppState) { } } + if recorded_addresses != own_addresses { + let path = addresses_path(&local); + let value = json!(own_addresses); + match state + .mutate_doc(move |doc| store::write_path(doc, &path, &value)) + .await + { + Ok(()) => info!(addresses = ?own_addresses, "Addresses updated in the member list"), + Err(error) => warn!(error = %error, "Failed to record our addresses"), + } + } + if recorded_alias == wanted { return; } |
