aboutsummaryrefslogtreecommitdiffstats
path: root/src/swarm/members.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/swarm/members.rs')
-rw-r--r--src/swarm/members.rs65
1 files changed, 61 insertions, 4 deletions
diff --git a/src/swarm/members.rs b/src/swarm/members.rs
index 05c6501..a534c04 100644
--- a/src/swarm/members.rs
+++ b/src/swarm/members.rs
@@ -10,7 +10,8 @@
//!
//! 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), where it can be reached (`addresses`, as its transport gives them:
+//! key stays that), where people reach its dashboard (`--dashboard-url`, `dashboard`),
+//! 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.
@@ -114,6 +115,34 @@ fn set_alias(doc: &mut impl Transactable, pk: &str, alias: Option<&str>) -> Resu
}
}
+fn dashboard_path(pk: &str) -> Vec<String> {
+ let mut path = member_path(pk);
+ path.push("dashboard".to_owned());
+ path
+}
+
+/// Where people reach `pk`'s dashboard, if it says.
+pub(crate) fn dashboard(doc: &Document, pk: &str) -> Option<String> {
+ match store::read_path(doc, &dashboard_path(pk)) {
+ Ok(Some(JsonValue::String(url))) => Some(url),
+ _ => None,
+ }
+}
+
+fn set_dashboard(
+ doc: &mut impl Transactable,
+ pk: &str,
+ url: Option<&str>,
+) -> Result<(), StoreError> {
+ match url {
+ Some(url) => store::write_path(doc, &dashboard_path(pk), &json!(url)),
+ None => match store::delete_path(doc, &dashboard_path(pk), false) {
+ Err(StoreError::NotFound) => Ok(()),
+ result => result,
+ },
+ }
+}
+
fn addresses_path(pk: &str) -> Vec<String> {
let mut path = member_path(pk);
path.push("addresses".to_owned());
@@ -260,8 +289,9 @@ const RENEWAL_MOST_OFTEN: Duration = Duration::from_secs(3600);
pub(crate) const MIN_ELECTORATE_WINDOW: Duration =
Duration::from_secs(7 * RENEWAL_MOST_OFTEN.as_secs());
-/// 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 its
+/// Registers this node if it is ready and its entry is missing, keeps its alias and its
+/// dashboard's URL as configured (set, changed or removed after a restart with another
+/// `--alias` or `--dashboard-url`) 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) {
@@ -271,7 +301,15 @@ pub(crate) async fn ensure_registered(state: &AppState) {
let local = state.local_id().to_owned();
let own = member_path(&local);
let window = state.electorate_window.as_millis() as u64;
- let (registered, recorded_alias, recorded_addresses, alive, recorded_window, shortest) = {
+ let (
+ registered,
+ recorded_alias,
+ recorded_dashboard,
+ recorded_addresses,
+ alive,
+ recorded_window,
+ shortest,
+ ) = {
let replica = state.doc.read().await;
let registered = store::read_path(&replica.doc, &own)
.ok()
@@ -280,6 +318,7 @@ pub(crate) async fn ensure_registered(state: &AppState) {
(
registered,
alias(&replica.doc, &local),
+ dashboard(&replica.doc, &local),
addresses(&replica.doc, &local),
millis_at(&replica.doc, &alive_path(&local)),
millis_at(&replica.doc, &window_path(&local)),
@@ -301,6 +340,9 @@ pub(crate) async fn ensure_registered(state: &AppState) {
if let Some(alias) = &wanted {
entry["alias"] = json!(alias);
}
+ if let Some(url) = &state.dashboard_url {
+ entry["dashboard"] = json!(url);
+ }
match state
.mutate_doc(move |doc| store::write_path(doc, &own, &entry))
.await
@@ -352,6 +394,21 @@ pub(crate) async fn ensure_registered(state: &AppState) {
}
}
+ if recorded_dashboard != state.dashboard_url {
+ let url = state.dashboard_url.clone();
+ let local = local.clone();
+ match state
+ .mutate_doc(move |doc| set_dashboard(doc, &local, url.as_deref()))
+ .await
+ {
+ Ok(()) => info!(
+ url = state.dashboard_url.as_deref(),
+ "Dashboard URL updated in the member list"
+ ),
+ Err(error) => warn!(error = %error, "Failed to record our dashboard URL"),
+ }
+ }
+
if recorded_alias == wanted {
return;
}