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:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-13 19:59:36 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-13 19:59:36 +0000
commite922e14e3ec4b898c111b2100cd63dddbe2fcdb1 (patch)
tree8fa2343b4b12ce97108b1e3461410e97a7af8cce /src/sync/mod.rs
parent8c903c9449d387c9b0edefa5aa283b176a3ed0cb (diff)
feat: add SyncLevel to sync system for purgatory announcement state-only sync
Purgatory announcements need state events (kind 30618) synced from external relays, but not full L2/L3 events (patches, issues, PRs) which would be rejected anyway. This implements the SyncLevel concept from the design doc (decision #6): - Add SyncLevel enum (Full vs StateOnly) to RepoSyncNeeds - When announcement enters purgatory during sync, register in RepoSyncIndex with SyncLevel::StateOnly - Add build_sync_level_aware_filters() that partitions repos by level: StateOnly repos only get state event filters (kind 30618) - Update derive_relay_targets to track state_only_repos separately - Update compute_actions to handle both repo sets - SelfSubscriber always uses SyncLevel::Full (promoted repos)
Diffstat (limited to 'src/sync/mod.rs')
-rw-r--r--src/sync/mod.rs59
1 files changed, 58 insertions, 1 deletions
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
index 1ee1872..519017b 100644
--- a/src/sync/mod.rs
+++ b/src/sync/mod.rs
@@ -85,6 +85,19 @@ use rejected_index::RejectedEventsIndex;
85// Supporting Data Structures 85// Supporting Data Structures
86// ============================================================================= 86// =============================================================================
87 87
88/// Level of sync needed for a repository
89///
90/// Purgatory announcements only need state events synced (to validate git data).
91/// Promoted repos need full L2/L3 sync (patches, issues, PRs, etc.).
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
93pub enum SyncLevel {
94 /// Full L2 + L3 sync (promoted repos with git data)
95 #[default]
96 Full,
97 /// Only state events (kind 30618) - for purgatory announcements
98 StateOnly,
99}
100
88/// What repos and root events need to be synced 101/// What repos and root events need to be synced
89#[derive(Debug, Clone, Default)] 102#[derive(Debug, Clone, Default)]
90pub struct RepoSyncNeeds { 103pub struct RepoSyncNeeds {
@@ -92,6 +105,8 @@ pub struct RepoSyncNeeds {
92 pub relays: HashSet<String>, 105 pub relays: HashSet<String>,
93 /// Root event IDs - 1617/1618/1621 - that reference this repo 106 /// Root event IDs - 1617/1618/1621 - that reference this repo
94 pub root_events: HashSet<EventId>, 107 pub root_events: HashSet<EventId>,
108 /// Sync level - StateOnly for purgatory, Full for promoted repos
109 pub sync_level: SyncLevel,
95} 110}
96 111
97/// Connection status for a relay 112/// Connection status for a relay
@@ -1677,6 +1692,7 @@ impl SyncManager {
1677 let eose_tx = self.eose_tx.as_ref().unwrap().clone(); 1692 let eose_tx = self.eose_tx.as_ref().unwrap().clone();
1678 let metrics_clone = self.metrics.clone(); 1693 let metrics_clone = self.metrics.clone();
1679 let pending_sync_index = Arc::clone(&self.pending_sync_index); 1694 let pending_sync_index = Arc::clone(&self.pending_sync_index);
1695 let repo_sync_index = Arc::clone(&self.repo_sync_index);
1680 let health_tracker = Arc::clone(&self.health_tracker); 1696 let health_tracker = Arc::clone(&self.health_tracker);
1681 let rejected_events_index = Arc::clone(&self.rejected_events_index); 1697 let rejected_events_index = Arc::clone(&self.rejected_events_index);
1682 1698
@@ -1719,8 +1735,49 @@ impl SyncManager {
1719 // For sync-triggered events that go to purgatory, trigger immediate sync 1735 // For sync-triggered events that go to purgatory, trigger immediate sync
1720 // (instead of the default 3-minute delay for user-submitted events) 1736 // (instead of the default 3-minute delay for user-submitted events)
1721 if result == ProcessResult::Purgatory { 1737 if result == ProcessResult::Purgatory {
1738 // Announcement events (kind 30617) - register in RepoSyncIndex with StateOnly
1739 // so that state events (kind 30618) are synced for this purgatory announcement
1740 if event.kind == Kind::GitRepoAnnouncement {
1741 if let Some(identifier) = event.tags.iter().find_map(|tag| {
1742 let tag_vec = tag.as_slice();
1743 if tag_vec.len() >= 2 && tag_vec[0] == "d" {
1744 Some(tag_vec[1].to_string())
1745 } else {
1746 None
1747 }
1748 }) {
1749 let repo_id = format!("30617:{}:{}", event.pubkey, identifier);
1750
1751 // Extract relay URLs from the purgatory entry
1752 let relays = write_policy
1753 .purgatory()
1754 .find_announcement(&event.pubkey, &identifier)
1755 .map(|entry| entry.relays)
1756 .unwrap_or_default();
1757
1758 tracing::info!(
1759 event_id = %event.id,
1760 repo_id = %repo_id,
1761 relay_count = relays.len(),
1762 "Registering purgatory announcement in RepoSyncIndex with StateOnly level"
1763 );
1764
1765 // Register in RepoSyncIndex with StateOnly level
1766 let mut index = repo_sync_index.write().await;
1767 let entry = index
1768 .entry(repo_id)
1769 .or_insert_with(|| RepoSyncNeeds {
1770 relays: HashSet::new(),
1771 root_events: HashSet::new(),
1772 sync_level: SyncLevel::StateOnly,
1773 });
1774 entry.relays.extend(relays);
1775 // Don't upgrade sync_level if already Full
1776 // (e.g., if announcement was promoted before this runs)
1777 }
1778 }
1722 // State events (kind 30618) - extract identifier and trigger immediate sync 1779 // State events (kind 30618) - extract identifier and trigger immediate sync
1723 if event.kind.as_u16() == 30618 { 1780 else if event.kind.as_u16() == 30618 {
1724 if let Some(identifier) = event.tags.iter().find_map(|tag| { 1781 if let Some(identifier) = event.tags.iter().find_map(|tag| {
1725 let tag_vec = tag.clone().to_vec(); 1782 let tag_vec = tag.clone().to_vec();
1726 if tag_vec.len() >= 2 && tag_vec[0] == "d" { 1783 if tag_vec.len() >= 2 && tag_vec[0] == "d" {