summaryrefslogtreecommitdiffstats
path: root/src/swarm/members.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-24 06:53:17 +0200
committertv <tv@krebsco.de>2026-10-24 06:53:17 +0200
commit8ee3b7f0d2f9b76cb24f0049431bd58d09d6c5a4 (patch)
tree6e9774ff74634029309e6720e7c8eccce62766cf /src/swarm/members.rs
parenteeae01887aa7bf5ab4dc4d9c5dc90e06c465accd (diff)
add node aliases
Diffstat (limited to 'src/swarm/members.rs')
-rw-r--r--src/swarm/members.rs89
1 files changed, 78 insertions, 11 deletions
diff --git a/src/swarm/members.rs b/src/swarm/members.rs
index e64dd20..e02dba4 100644
--- a/src/swarm/members.rs
+++ b/src/swarm/members.rs
@@ -7,6 +7,12 @@
//! while it is alive. An operator's forget (`DELETE /peers/{pk}`) removes the entry
//! together with writing the forget record; a forgotten node that turns out to be alive
//! cancels the record and registers again.
+//!
+//! Besides its tier, an entry holds the alias a node gives itself (`--alias`), a name
+//! for people reading /peers, metrics and logs. Not unique and never an identity: the
+//! public key stays that.
+
+use std::collections::HashMap;
use automerge::AutoCommit;
use serde_json::{Value as JsonValue, json};
@@ -69,27 +75,88 @@ pub(crate) fn set_tier(doc: &mut AutoCommit, pk: &str, tier: Tier) -> Result<(),
store::write_path(doc, &tier_path(pk), &json!(tier.as_str()))
}
-/// Registers this node if it is ready and its entry is missing.
+fn alias_path(pk: &str) -> Vec<String> {
+ let mut path = member_path(pk);
+ path.push("alias".to_owned());
+ path
+}
+
+/// `pk`'s alias, if it gave itself one.
+pub(crate) fn alias(doc: &AutoCommit, pk: &str) -> Option<String> {
+ match store::read_path(doc, &alias_path(pk)) {
+ Ok(Some(JsonValue::String(alias))) => Some(alias),
+ _ => None,
+ }
+}
+
+/// The aliases of all members that have one.
+pub(crate) fn aliases(doc: &AutoCommit) -> HashMap<String, String> {
+ members(doc)
+ .into_iter()
+ .filter_map(|pk| alias(doc, &pk).map(|alias| (pk, alias)))
+ .collect()
+}
+
+fn set_alias(doc: &mut AutoCommit, pk: &str, alias: Option<&str>) -> Result<(), StoreError> {
+ match alias {
+ Some(alias) => store::write_path(doc, &alias_path(pk), &json!(alias)),
+ None => match store::delete_path(doc, &alias_path(pk), false) {
+ Err(StoreError::NotFound) => Ok(()),
+ result => result,
+ },
+ }
+}
+
+/// Registers this node if it is ready and its entry is missing, and keeps its alias
+/// as configured (set, changed or removed after a restart with another `--alias`).
pub(crate) async fn ensure_registered(state: &AppState) {
if !state.is_ready().await {
return;
}
- let own = member_path(state.local_id());
- let registered = store::read_path(&state.doc.read().await.doc, &own)
- .ok()
- .flatten()
- .is_some();
- if registered {
+ let local = state.local_id().to_owned();
+ let own = member_path(&local);
+ let (registered, recorded_alias) = {
+ let replica = state.doc.read().await;
+ let registered = store::read_path(&replica.doc, &own)
+ .ok()
+ .flatten()
+ .is_some();
+ (registered, alias(&replica.doc, &local))
+ };
+ let wanted = state.alias.clone();
+
+ if !registered {
+ let mut entry = json!({ "since": unix_millis() });
+ if let Some(alias) = &wanted {
+ entry["alias"] = json!(alias);
+ }
+ match state
+ .mutate_doc(move |doc| store::write_path(doc, &own, &entry))
+ .await
+ {
+ Ok(()) => info!(
+ alias = wanted.as_deref(),
+ "Registered in the swarm's member list"
+ ),
+ Err(error) => warn!(error = %error, "Failed to register in the member list"),
+ }
return;
}
- let entry = json!({ "since": unix_millis() });
+ if recorded_alias == wanted {
+ return;
+ }
+ let alias = wanted.clone();
match state
- .mutate_doc(move |doc| store::write_path(doc, &own, &entry))
+ .mutate_doc(move |doc| set_alias(doc, &local, alias.as_deref()))
.await
{
- Ok(()) => info!("Registered in the swarm's member list"),
- Err(error) => warn!(error = %error, "Failed to register in the member list"),
+ Ok(()) => info!(
+ alias = wanted.as_deref(),
+ previous = recorded_alias.as_deref(),
+ "Alias updated in the member list"
+ ),
+ Err(error) => warn!(error = %error, "Failed to record our alias"),
}
}