diff --git a/core/archipelago/src/bootstrap.rs b/core/archipelago/src/bootstrap.rs index 72499f3b..459c7b08 100644 --- a/core/archipelago/src/bootstrap.rs +++ b/core/archipelago/src/bootstrap.rs @@ -65,7 +65,9 @@ pub async fn ensure_doctor_installed() { Err(e) => warn!("Nginx bootstrap failed (non-fatal): {:#}", e), } match run_bitcoin_rpc_repair().await { - Ok(true) => info!("Repaired Bitcoin RPC bind settings; running Bitcoin containers left untouched"), + Ok(true) => { + info!("Repaired Bitcoin RPC bind settings; running Bitcoin containers left untouched") + } Ok(false) => debug!("Bitcoin RPC bind settings already usable"), Err(e) => warn!("Bitcoin RPC repair failed (non-fatal): {:#}", e), } diff --git a/core/archipelago/src/container/quadlet.rs b/core/archipelago/src/container/quadlet.rs index 0734e978..c142b6da 100644 --- a/core/archipelago/src/container/quadlet.rs +++ b/core/archipelago/src/container/quadlet.rs @@ -298,7 +298,11 @@ fn shell_join(parts: &[String]) -> String { fn quote_environment(env: &str) -> String { let env = env.replace(['\r', '\n'], " "); - if env.is_empty() || env.chars().any(|c| c.is_whitespace() || "\"\\$`".contains(c)) { + if env.is_empty() + || env + .chars() + .any(|c| c.is_whitespace() || "\"\\$`".contains(c)) + { let escaped = env .replace('\\', "\\\\") .replace('"', "\\\"") @@ -793,7 +797,10 @@ mod tests { #[test] fn quote_environment_quotes_values_with_spaces() { - assert_eq!(quote_environment("BITCOIN_RPC_PASS=secret"), "BITCOIN_RPC_PASS=secret"); + assert_eq!( + quote_environment("BITCOIN_RPC_PASS=secret"), + "BITCOIN_RPC_PASS=secret" + ); assert_eq!( quote_environment("RELAY_NAME=Archipelago Nostr Relay"), "\"RELAY_NAME=Archipelago Nostr Relay\"" diff --git a/core/archipelago/src/health_monitor.rs b/core/archipelago/src/health_monitor.rs index 3d5cc456..c37fc3ff 100644 --- a/core/archipelago/src/health_monitor.rs +++ b/core/archipelago/src/health_monitor.rs @@ -514,7 +514,14 @@ async fn cleanup_stale_podman_healthcheck_units(live_container_ids: &HashSet) -> Vec { let mut units = Vec::new(); for args in [ - ["--user", "list-timers", "--all", "--no-legend", "--no-pager"].as_slice(), + [ + "--user", + "list-timers", + "--all", + "--no-legend", + "--no-pager", + ] + .as_slice(), ["--user", "list-units", "--all", "--no-legend", "--no-pager"].as_slice(), ] { let output = match tokio::time::timeout( @@ -833,6 +840,21 @@ pub fn spawn_health_monitor(state: Arc, data_dir: PathBuf) { } } + let unhealthy_app_ids: HashSet<&str> = unhealthy + .iter() + .map(|container| container.app_id.as_str()) + .collect(); + let before = data.notifications.len(); + data.notifications.retain(|n| { + !n.id.starts_with("health-") + || n.app_id + .as_deref() + .is_some_and(|app_id| unhealthy_app_ids.contains(app_id)) + }); + if data.notifications.len() != before { + state_changed = true; + } + // Sort by startup tier: databases first, then core, then dependent, then apps, then UIs unhealthy.sort_by_key(|c| container_tier(&c.name)); @@ -1346,7 +1368,9 @@ mod tests { ); assert_eq!(parse_podman_healthcheck_unit("grafana.service"), None); assert_eq!( - parse_podman_healthcheck_unit("nothexzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz-x.timer"), + parse_podman_healthcheck_unit( + "nothexzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz-x.timer" + ), None ); }