upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/main.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/main.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/main.rs')
-rw-r--r--src/main.rs21
1 files changed, 15 insertions, 6 deletions
diff --git a/src/main.rs b/src/main.rs
index dd2c903..bf3aefb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -130,7 +130,9 @@ async fn main() -> Result<()> {
130 } 130 }
131 131
132 // Get a reference to the rejected events index for shutdown persistence 132 // Get a reference to the rejected events index for shutdown persistence
133 // and for the HTTP server's git push path (hot-cache re-processing)
133 let shutdown_rejected_index = sync_manager.rejected_events_index(); 134 let shutdown_rejected_index = sync_manager.rejected_events_index();
135 let http_rejected_index = shutdown_rejected_index.clone();
134 136
135 tokio::spawn(async move { 137 tokio::spawn(async move {
136 sync_manager.run().await; 138 sync_manager.run().await;
@@ -142,11 +144,11 @@ async fn main() -> Result<()> {
142 let mut interval = tokio::time::interval(Duration::from_secs(60)); 144 let mut interval = tokio::time::interval(Duration::from_secs(60));
143 loop { 145 loop {
144 interval.tick().await; 146 interval.tick().await;
145 let (state_removed, pr_removed) = cleanup_purgatory.cleanup(); 147 let (announcement_removed, state_removed, pr_removed) = cleanup_purgatory.cleanup();
146 if state_removed > 0 || pr_removed > 0 { 148 if announcement_removed > 0 || state_removed > 0 || pr_removed > 0 {
147 info!( 149 info!(
148 "Purgatory cleanup: removed {} state events, {} PR events", 150 "Purgatory cleanup: removed {} announcements, {} state events, {} PR events",
149 state_removed, pr_removed 151 announcement_removed, state_removed, pr_removed
150 ); 152 );
151 } 153 }
152 } 154 }
@@ -206,12 +208,15 @@ async fn main() -> Result<()> {
206 // Start HTTP server with integrated relay and database 208 // Start HTTP server with integrated relay and database
207 info!("Starting HTTP server on {}", config.bind_address); 209 info!("Starting HTTP server on {}", config.bind_address);
208 210
211 // Wrap write_policy in Arc for sharing between HTTP server connections
212 let http_write_policy = Arc::new(relay_with_db.write_policy.clone());
213
209 // Run server until shutdown signal, then cleanup 214 // Run server until shutdown signal, then cleanup
210 #[cfg(unix)] 215 #[cfg(unix)]
211 { 216 {
212 use tokio::signal::unix::{signal, SignalKind}; 217 use tokio::signal::unix::{signal, SignalKind};
213 let mut sigterm = signal(SignalKind::terminate())?; 218 let mut sigterm = signal(SignalKind::terminate())?;
214 219
215 tokio::select! { 220 tokio::select! {
216 result = http::run_server( 221 result = http::run_server(
217 config, 222 config,
@@ -219,6 +224,8 @@ async fn main() -> Result<()> {
219 relay_with_db.database, 224 relay_with_db.database,
220 metrics, 225 metrics,
221 purgatory, 226 purgatory,
227 http_write_policy,
228 http_rejected_index,
222 ) => { 229 ) => {
223 result? 230 result?
224 } 231 }
@@ -230,7 +237,7 @@ async fn main() -> Result<()> {
230 } 237 }
231 } 238 }
232 } 239 }
233 240
234 #[cfg(not(unix))] 241 #[cfg(not(unix))]
235 { 242 {
236 tokio::select! { 243 tokio::select! {
@@ -240,6 +247,8 @@ async fn main() -> Result<()> {
240 relay_with_db.database, 247 relay_with_db.database,
241 metrics, 248 metrics,
242 purgatory, 249 purgatory,
250 http_write_policy,
251 http_rejected_index,
243 ) => { 252 ) => {
244 result? 253 result?
245 } 254 }