upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/purgatory/sync/context.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 /src/purgatory/sync/context.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 'src/purgatory/sync/context.rs')
-rw-r--r--src/purgatory/sync/context.rs24
1 files changed, 21 insertions, 3 deletions
diff --git a/src/purgatory/sync/context.rs b/src/purgatory/sync/context.rs
index 904f8af..8297515 100644
--- a/src/purgatory/sync/context.rs
+++ b/src/purgatory/sync/context.rs
@@ -75,7 +75,12 @@ pub trait SyncContext: Send + Sync {
75 /// # Returns 75 /// # Returns
76 /// Set of clone URLs from PR events in purgatory for this identifier 76 /// Set of clone URLs from PR events in purgatory for this identifier
77 fn collect_pr_clone_urls(&self, identifier: &str) -> HashSet<String>; 77 fn collect_pr_clone_urls(&self, identifier: &str) -> HashSet<String>;
78 /// Get repository data (announcements, clone URLs, etc.) from the database. 78 /// Get repository data (announcements, clone URLs, etc.) from the database and purgatory.
79 ///
80 /// Checks both the database (promoted announcements) and purgatory (announcements
81 /// awaiting git data). This is necessary to obtain clone URLs when an announcement
82 /// has not yet been promoted - without purgatory data, the sync loop would have no
83 /// URLs to fetch from and the announcement could never be promoted (circular deadlock).
79 /// 84 ///
80 /// # Arguments 85 /// # Arguments
81 /// * `identifier` - The repository identifier (d-tag value) 86 /// * `identifier` - The repository identifier (d-tag value)
@@ -279,7 +284,16 @@ impl SyncContext for RealSyncContext {
279 } 284 }
280 285
281 async fn fetch_repository_data(&self, identifier: &str) -> Result<RepositoryData> { 286 async fn fetch_repository_data(&self, identifier: &str) -> Result<RepositoryData> {
282 crate::git::authorization::fetch_repository_data(&self.database, identifier).await 287 // Use the purgatory-aware variant so that clone URLs from announcements still
288 // in purgatory (not yet promoted) are available. Without this, the sync loop
289 // would find no URLs to fetch from and the announcement could never be promoted
290 // (circular deadlock: can't promote without git data, can't get git data without URLs).
291 crate::git::authorization::fetch_repository_data_with_purgatory(
292 &self.database,
293 &self.purgatory,
294 identifier,
295 )
296 .await
283 } 297 }
284 298
285 fn collect_needed_oids(&self, identifier: &str) -> HashSet<String> { 299 fn collect_needed_oids(&self, identifier: &str) -> HashSet<String> {
@@ -487,7 +501,9 @@ impl SyncContext for RealSyncContext {
487 source_repo_path: &Path, 501 source_repo_path: &Path,
488 new_oids: &HashSet<String>, 502 new_oids: &HashSet<String>,
489 ) -> Result<ProcessResult> { 503 ) -> Result<ProcessResult> {
490 // Delegate to the unified function from git::sync 504 // Delegate to the unified function from git::sync.
505 // Pass None for write_policy and rejected_events_index: the purgatory sync path
506 // already handles hot-cache re-processing via SyncManager::process_event_static.
491 let result = crate::git::sync::process_newly_available_git_data( 507 let result = crate::git::sync::process_newly_available_git_data(
492 source_repo_path, 508 source_repo_path,
493 new_oids, 509 new_oids,
@@ -495,6 +511,8 @@ impl SyncContext for RealSyncContext {
495 self.local_relay.as_ref(), 511 self.local_relay.as_ref(),
496 &self.purgatory, 512 &self.purgatory,
497 &self.git_data_path, 513 &self.git_data_path,
514 None,
515 None,
498 ) 516 )
499 .await?; 517 .await?;
500 518