From 26f608e5011b9d1ad6036da75b89272835e69695 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Mon, 23 Feb 2026 15:08:37 +0000 Subject: persist and restore announcement events across graceful restarts Extends purgatory persistence to include announcement purgatory entries. On graceful shutdown, non-soft-expired announcements are serialised to purgatory-state.json alongside state/PR/expired events; on startup they are restored, skipping any entry whose bare repo path no longer exists. Updates purgatory-design.md to reflect that purgatory persists through graceful shutdown and documents the new PurgatoryState disk format. Adds create_announcement_event helper to purgatory_helpers and three new integration tests in purgatory_persistence covering the full save/restore cycle, missing-repo skip, and the combined roundtrip with all entry types. --- tests/common/purgatory_helpers.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'tests/common/purgatory_helpers.rs') diff --git a/tests/common/purgatory_helpers.rs b/tests/common/purgatory_helpers.rs index 1d06f22..cfcea1c 100644 --- a/tests/common/purgatory_helpers.rs +++ b/tests/common/purgatory_helpers.rs @@ -338,6 +338,44 @@ pub fn build_repo_coord(keys: &Keys, identifier: &str) -> String { format!("30617:{}:{}", keys.public_key().to_hex(), identifier) } +/// Create a repository announcement event (kind 30617) for purgatory tests. +/// +/// Creates a minimal but valid NIP-34 repository announcement with a `d` tag, +/// optional `clone` URLs, and optional `relays` URLs. +/// +/// # Arguments +/// * `keys` - Keys for signing +/// * `identifier` - Repository identifier (d-tag) +/// * `clone_urls` - Clone URLs to include (may be empty) +/// * `relay_urls` - Relay URLs to include (may be empty) +/// +/// # Returns +/// * `Ok(Event)` - Signed announcement event +/// * `Err(String)` - If signing fails +pub fn create_announcement_event( + keys: &Keys, + identifier: &str, + clone_urls: &[&str], + relay_urls: &[&str], +) -> Result { + let mut tags = vec![Tag::identifier(identifier)]; + + if !clone_urls.is_empty() { + let urls: Vec = clone_urls.iter().map(|s| s.to_string()).collect(); + tags.push(Tag::custom(TagKind::custom("clone"), urls)); + } + + if !relay_urls.is_empty() { + let urls: Vec = relay_urls.iter().map(|s| s.to_string()).collect(); + tags.push(Tag::custom(TagKind::custom("relays"), urls)); + } + + EventBuilder::new(Kind::GitRepoAnnouncement, "") + .tags(tags) + .sign_with_keys(keys) + .map_err(|e| format!("Failed to sign announcement event: {}", e)) +} + /// Wait for an event to be served by a relay (not in purgatory). /// /// Polls the relay until the event is queryable, indicating it has -- cgit v1.2.3