upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/sync/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sync/mod.rs')
-rw-r--r--src/sync/mod.rs116
1 files changed, 115 insertions, 1 deletions
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
index fe336d1..35a8afb 100644
--- a/src/sync/mod.rs
+++ b/src/sync/mod.rs
@@ -2050,6 +2050,119 @@ impl SyncManager {
2050 broadcast = broadcast_success, 2050 broadcast = broadcast_success,
2051 "Synced event saved and broadcast" 2051 "Synced event saved and broadcast"
2052 ); 2052 );
2053
2054 // GRASP-02 PR3: Invalidate and re-process maintainer announcements
2055 // If this is a repository announcement that lists maintainers, check if any
2056 // of those maintainer announcements were previously rejected and are still
2057 // in the hot cache. If so, re-process them immediately (they should now pass
2058 // validation since the owner announcement has been accepted).
2059 if event.kind == Kind::GitRepoAnnouncement {
2060 use crate::nostr::events::RepositoryAnnouncement;
2061
2062 match RepositoryAnnouncement::from_event(event.clone()) {
2063 Ok(announcement) => {
2064 if !announcement.maintainers.is_empty() {
2065 tracing::debug!(
2066 event_id = %event.id,
2067 identifier = %announcement.identifier,
2068 maintainer_count = announcement.maintainers.len(),
2069 "Owner announcement accepted, checking for rejected maintainer announcements"
2070 );
2071
2072 // For each maintainer, invalidate and get their events
2073 for maintainer_hex in &announcement.maintainers {
2074 // Parse maintainer public key
2075 match PublicKey::from_hex(maintainer_hex) {
2076 Ok(maintainer_pubkey) => {
2077 let (removed, hot_events) = rejected_events_index
2078 .invalidate_and_get_events(
2079 &maintainer_pubkey,
2080 &announcement.identifier,
2081 );
2082
2083 if removed > 0 {
2084 tracing::info!(
2085 maintainer = %maintainer_hex,
2086 identifier = %announcement.identifier,
2087 removed_from_cold_index = removed,
2088 hot_cache_events = hot_events.len(),
2089 "Invalidated rejected maintainer announcements"
2090 );
2091 }
2092
2093 // Re-process events from hot cache immediately
2094 for maintainer_event in hot_events {
2095 tracing::info!(
2096 event_id = %maintainer_event.id,
2097 maintainer = %maintainer_hex,
2098 identifier = %announcement.identifier,
2099 "Re-processing maintainer announcement from hot cache"
2100 );
2101
2102 // Recursive call to process_event_static
2103 // This is safe because:
2104 // 1. Event was removed from hot cache before this call
2105 // 2. Second attempt uses maintainer exception (different code path)
2106 // 3. If second attempt fails, stays in cold index only (no third attempt)
2107 // Use Box::pin to avoid infinitely sized future
2108 let reprocess_result = Box::pin(Self::process_event_static(
2109 &maintainer_event,
2110 relay_url,
2111 database,
2112 write_policy,
2113 local_relay,
2114 rejected_events_index,
2115 ))
2116 .await;
2117
2118 match reprocess_result {
2119 ProcessResult::Saved => {
2120 tracing::info!(
2121 event_id = %maintainer_event.id,
2122 maintainer = %maintainer_hex,
2123 identifier = %announcement.identifier,
2124 "Maintainer announcement accepted on re-processing"
2125 );
2126 }
2127 ProcessResult::Duplicate => {
2128 tracing::debug!(
2129 event_id = %maintainer_event.id,
2130 "Maintainer announcement already exists (duplicate)"
2131 );
2132 }
2133 other => {
2134 tracing::warn!(
2135 event_id = %maintainer_event.id,
2136 maintainer = %maintainer_hex,
2137 identifier = %announcement.identifier,
2138 result = ?other,
2139 "Maintainer announcement still rejected on re-processing"
2140 );
2141 }
2142 }
2143 }
2144 }
2145 Err(e) => {
2146 tracing::warn!(
2147 maintainer_hex = %maintainer_hex,
2148 error = %e,
2149 "Invalid maintainer public key in announcement"
2150 );
2151 }
2152 }
2153 }
2154 }
2155 }
2156 Err(e) => {
2157 tracing::warn!(
2158 event_id = %event.id,
2159 error = %e,
2160 "Failed to parse repository announcement for maintainer invalidation"
2161 );
2162 }
2163 }
2164 }
2165
2053 ProcessResult::Saved 2166 ProcessResult::Saved
2054 } 2167 }
2055 WritePolicyResult::Reject { message, status } => { 2168 WritePolicyResult::Reject { message, status } => {
@@ -2082,7 +2195,8 @@ impl SyncManager {
2082 .and_then(|t| t.content()) 2195 .and_then(|t| t.content())
2083 { 2196 {
2084 // Determine rejection reason based on message 2197 // Determine rejection reason based on message
2085 let reason = if message.contains("doesn't list this service") { 2198 let reason = if message.contains("doesn't list this service")
2199 || message.contains("Announcement must list service") {
2086 rejected_index::RejectionReason::DoesNotListService 2200 rejected_index::RejectionReason::DoesNotListService
2087 } else if message.contains("maintainer") { 2201 } else if message.contains("maintainer") {
2088 rejected_index::RejectionReason::MaintainerNotYetValid 2202 rejected_index::RejectionReason::MaintainerNotYetValid