use crate::discovery::DiscoveredRepo; use crate::health::GraspServer; use anyhow::{Context, Result}; use nostr_sdk::prelude::*; pub struct OptionalSigner { keys: Option, } impl OptionalSigner { pub fn none() -> Self { Self { keys: None } } pub fn from_nsec(nsec: &str) -> Result { let keys = Keys::parse(nsec).context("failed to parse nsec")?; Ok(Self { keys: Some(keys) }) } pub fn is_available(&self) -> bool { self.keys.is_some() } pub async fn build_updated_announcement( &self, original: &DiscoveredRepo, additional_servers: &[GraspServer], ) -> Result> { let keys = match &self.keys { Some(k) => k, None => { tracing::debug!("no signer available, skipping announcement update"); return Ok(None); } }; if additional_servers.is_empty() { return Ok(None); } let pk_hex = original.pubkey.to_hex(); let mut new_clone_urls: Vec = original.clone_urls.clone(); for server in additional_servers { let url = server.clone_url(&pk_hex, &original.identifier); if !new_clone_urls.contains(&url) { new_clone_urls.push(url); } } let mut tags: Vec = vec![ Tag::custom(TagKind::Custom("d".into()), [&original.identifier]), ]; for url in &new_clone_urls { tags.push(Tag::custom(TagKind::Custom("clone".into()), [url.as_str()])); } for url in &original.relay_urls { tags.push(Tag::custom( TagKind::Custom("relays".into()), [url.as_str()], )); } let builder = EventBuilder::new(Kind::Custom(30617), "").tags(tags); let event = builder.sign_with_keys(keys)?; tracing::info!( identifier = %original.identifier, added = additional_servers.len(), "built updated announcement with additional clone URLs" ); Ok(Some(event)) } }