upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit/src/client.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-23 15:41:32 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-23 15:41:32 +0000
commitc54ce061d6d278cce8362d5af085808ca60c239b (patch)
treeec967d6195d9f7ec4f061449596611afe3a0950f /grasp-audit/src/client.rs
parente0ad39a489b3398f8208713bf728db0cb11475b0 (diff)
parent113928aa84894ea8f65c247d9987527e792b32a9 (diff)
feat: announcement purgatory
Extends purgatory to hold repository announcements until git data arrives, preventing empty repositories from being served to clients. When an announcement is received, a bare repo is created immediately and the announcement is held in purgatory. It is only promoted and served once a git push confirms real content exists. If no push arrives before expiry, the bare repo is deleted and the announcement is silently discarded. Key behaviours: - Soft expiry: announcements are hidden from clients but kept alive while git pushes are in progress, reviving on successful push - Expiry is extended when a matching state event or git push is observed - NIP-09 deletion events remove announcements from purgatory - Purgatory state (announcements, state events, PR events, expired set) is persisted to disk on graceful shutdown and restored on startup, with elapsed downtime subtracted from expiry deadlines - Purgatory announcements drive StateOnly sync in the sync system so state events are fetched from listed relays before promotion - SyncLevel added to RepoSyncIndex to distinguish purgatory repos (StateOnly) from promoted repos (Full L2+L3 sync)
Diffstat (limited to 'grasp-audit/src/client.rs')
-rw-r--r--grasp-audit/src/client.rs30
1 files changed, 30 insertions, 0 deletions
diff --git a/grasp-audit/src/client.rs b/grasp-audit/src/client.rs
index 91a93dc..5c263ad 100644
--- a/grasp-audit/src/client.rs
+++ b/grasp-audit/src/client.rs
@@ -209,6 +209,36 @@ impl AuditClient {
209 Ok(event_id) 209 Ok(event_id)
210 } 210 }
211 211
212 /// Send event and note whether it entered purgatory (not served) or was served immediately.
213 ///
214 /// This is a tolerant version of `send_event_expect_purgatory_not_served` that doesn't
215 /// fail if purgatory is not observed. It returns whether purgatory was observed so
216 /// fixtures can proceed regardless of relay implementation status.
217 ///
218 /// Returns (EventId, bool) where bool = true if event was NOT served (purgatory observed).
219 pub async fn send_event_and_note_purgatory(&self, event: Event) -> Result<(EventId, bool)> {
220 if self.config.read_only {
221 return Err(anyhow!("Client is in read-only mode"));
222 }
223
224 let output = self.client.send_event(&event).await?;
225 let event_id = *output.id();
226
227 // Check if any relay rejected the event and return the error message
228 if !output.failed.is_empty() {
229 let (relay_url, error) = output.failed.iter().next().unwrap();
230 return Err(anyhow!("Relay {} rejected event: {}", relay_url, error));
231 }
232
233 // Wait a bit for event to propagate
234 tokio::time::sleep(Duration::from_millis(300)).await;
235
236 // Check if event is served (not in purgatory) or not served (in purgatory)
237 let in_purgatory = !self.is_event_on_relay(event.id).await?;
238
239 Ok((event_id, in_purgatory))
240 }
241
212 /// check if an event is on the relay 242 /// check if an event is on the relay
213 pub async fn is_event_on_relay(&self, id: EventId) -> Result<bool> { 243 pub async fn is_event_on_relay(&self, id: EventId) -> Result<bool> {
214 Ok(!self 244 Ok(!self