upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audit_cleanup.rs24
-rw-r--r--src/git/handlers.rs66
-rw-r--r--src/git/sync.rs2
-rw-r--r--src/http/mod.rs1
-rw-r--r--src/nostr/builder.rs1
-rw-r--r--src/nostr/policy/announcement.rs18
-rw-r--r--src/nostr/policy/deletion.rs45
-rw-r--r--src/nostr/policy/pr_event.rs10
-rw-r--r--src/nostr/policy/state.rs6
-rw-r--r--src/purgatory/mod.rs51
-rw-r--r--src/sync/mod.rs3
11 files changed, 133 insertions, 94 deletions
diff --git a/src/audit_cleanup.rs b/src/audit_cleanup.rs
index b976b1f..de78b1b 100644
--- a/src/audit_cleanup.rs
+++ b/src/audit_cleanup.rs
@@ -15,7 +15,7 @@
15//! 15//!
16//! Runs every `AUDIT_CLEANUP_INTERVAL_SECS` seconds. 16//! Runs every `AUDIT_CLEANUP_INTERVAL_SECS` seconds.
17 17
18use std::path::PathBuf; 18use std::path::{Path, PathBuf};
19use std::time::Duration; 19use std::time::Duration;
20 20
21use nostr_sdk::prelude::*; 21use nostr_sdk::prelude::*;
@@ -46,8 +46,12 @@ pub async fn run_audit_cleanup_loop(database: SharedDatabase, git_data_path: Pat
46} 46}
47 47
48/// Perform a single cleanup pass. 48/// Perform a single cleanup pass.
49async fn run_audit_cleanup_once(database: &SharedDatabase, git_data_path: &PathBuf) { 49async fn run_audit_cleanup_once(database: &SharedDatabase, git_data_path: &Path) {
50 let cutoff = Timestamp::from(Timestamp::now().as_secs().saturating_sub(AUDIT_CLEANUP_AGE_SECS)); 50 let cutoff = Timestamp::from(
51 Timestamp::now()
52 .as_secs()
53 .saturating_sub(AUDIT_CLEANUP_AGE_SECS),
54 );
51 55
52 // --- Step 1: Find repo announcements to delete git repos for --- 56 // --- Step 1: Find repo announcements to delete git repos for ---
53 let repo_filter = Filter::new() 57 let repo_filter = Filter::new()
@@ -73,10 +77,7 @@ async fn run_audit_cleanup_once(database: &SharedDatabase, git_data_path: &PathB
73 if repo_path.exists() { 77 if repo_path.exists() {
74 match std::fs::remove_dir_all(&repo_path) { 78 match std::fs::remove_dir_all(&repo_path) {
75 Ok(()) => { 79 Ok(()) => {
76 debug!( 80 debug!("audit_cleanup: deleted git repo {}", repo_path.display());
77 "audit_cleanup: deleted git repo {}",
78 repo_path.display()
79 );
80 repos_deleted += 1; 81 repos_deleted += 1;
81 82
82 // Remove the parent npub directory if it is now empty 83 // Remove the parent npub directory if it is now empty
@@ -131,9 +132,7 @@ async fn run_audit_cleanup_once(database: &SharedDatabase, git_data_path: &PathB
131 } 132 }
132 133
133 // --- Step 2: Delete all audit events from the database --- 134 // --- Step 2: Delete all audit events from the database ---
134 let all_audit_filter = Filter::new() 135 let all_audit_filter = Filter::new().hashtag(AUDIT_TEST_EVENT_TAG).until(cutoff);
135 .hashtag(AUDIT_TEST_EVENT_TAG)
136 .until(cutoff);
137 136
138 match database.delete(all_audit_filter).await { 137 match database.delete(all_audit_filter).await {
139 Ok(()) => { 138 Ok(()) => {
@@ -143,7 +142,10 @@ async fn run_audit_cleanup_once(database: &SharedDatabase, git_data_path: &PathB
143 ); 142 );
144 } 143 }
145 Err(e) => { 144 Err(e) => {
146 error!("audit_cleanup: failed to delete audit events from database: {}", e); 145 error!(
146 "audit_cleanup: failed to delete audit events from database: {}",
147 e
148 );
147 } 149 }
148 } 150 }
149} 151}
diff --git a/src/git/handlers.rs b/src/git/handlers.rs
index 5ff3a7f..b615251 100644
--- a/src/git/handlers.rs
+++ b/src/git/handlers.rs
@@ -154,13 +154,10 @@ pub async fn handle_upload_pack(
154 154
155 // Write request to git's stdin 155 // Write request to git's stdin
156 if let Some(mut stdin) = git.take_stdin() { 156 if let Some(mut stdin) = git.take_stdin() {
157 stdin 157 stdin.write_all(&request_body).await.map_err(|e| {
158 .write_all(&request_body) 158 error!("Failed to write to git upload-pack stdin: {}", e);
159 .await 159 GitError::IoError(e)
160 .map_err(|e| { 160 })?;
161 error!("Failed to write to git upload-pack stdin: {}", e);
162 GitError::IoError(e)
163 })?;
164 // Close stdin to signal end of input 161 // Close stdin to signal end of input
165 drop(stdin); 162 drop(stdin);
166 } 163 }
@@ -171,24 +168,18 @@ pub async fn handle_upload_pack(
171 168
172 if let Some(stdout) = git.take_stdout() { 169 if let Some(stdout) = git.take_stdout() {
173 let mut stdout = stdout; 170 let mut stdout = stdout;
174 stdout 171 stdout.read_to_end(&mut output).await.map_err(|e| {
175 .read_to_end(&mut output) 172 error!("Failed to read git upload-pack stdout: {}", e);
176 .await 173 GitError::IoError(e)
177 .map_err(|e| { 174 })?;
178 error!("Failed to read git upload-pack stdout: {}", e);
179 GitError::IoError(e)
180 })?;
181 } 175 }
182 176
183 if let Some(stderr) = git.take_stderr() { 177 if let Some(stderr) = git.take_stderr() {
184 let mut stderr = stderr; 178 let mut stderr = stderr;
185 stderr 179 stderr.read_to_end(&mut stderr_output).await.map_err(|e| {
186 .read_to_end(&mut stderr_output) 180 error!("Failed to read git upload-pack stderr: {}", e);
187 .await 181 GitError::IoError(e)
188 .map_err(|e| { 182 })?;
189 error!("Failed to read git upload-pack stderr: {}", e);
190 GitError::IoError(e)
191 })?;
192 } 183 }
193 184
194 // Wait for process 185 // Wait for process
@@ -317,13 +308,10 @@ pub async fn handle_receive_pack(
317 308
318 // Write request to git's stdin 309 // Write request to git's stdin
319 if let Some(mut stdin) = git.take_stdin() { 310 if let Some(mut stdin) = git.take_stdin() {
320 stdin 311 stdin.write_all(&request_body).await.map_err(|e| {
321 .write_all(&request_body) 312 error!("Failed to write to git receive-pack stdin: {}", e);
322 .await 313 GitError::IoError(e)
323 .map_err(|e| { 314 })?;
324 error!("Failed to write to git receive-pack stdin: {}", e);
325 GitError::IoError(e)
326 })?;
327 drop(stdin); 315 drop(stdin);
328 } 316 }
329 317
@@ -333,24 +321,18 @@ pub async fn handle_receive_pack(
333 321
334 if let Some(stdout) = git.take_stdout() { 322 if let Some(stdout) = git.take_stdout() {
335 let mut stdout = stdout; 323 let mut stdout = stdout;
336 stdout 324 stdout.read_to_end(&mut output).await.map_err(|e| {
337 .read_to_end(&mut output) 325 error!("Failed to read git receive-pack stdout: {}", e);
338 .await 326 GitError::IoError(e)
339 .map_err(|e| { 327 })?;
340 error!("Failed to read git receive-pack stdout: {}", e);
341 GitError::IoError(e)
342 })?;
343 } 328 }
344 329
345 if let Some(stderr) = git.take_stderr() { 330 if let Some(stderr) = git.take_stderr() {
346 let mut stderr = stderr; 331 let mut stderr = stderr;
347 stderr 332 stderr.read_to_end(&mut stderr_output).await.map_err(|e| {
348 .read_to_end(&mut stderr_output) 333 error!("Failed to read git receive-pack stderr: {}", e);
349 .await 334 GitError::IoError(e)
350 .map_err(|e| { 335 })?;
351 error!("Failed to read git receive-pack stderr: {}", e);
352 GitError::IoError(e)
353 })?;
354 } 336 }
355 337
356 // Wait for process 338 // Wait for process
diff --git a/src/git/sync.rs b/src/git/sync.rs
index 9a02ad4..05dcbda 100644
--- a/src/git/sync.rs
+++ b/src/git/sync.rs
@@ -814,6 +814,7 @@ pub fn extract_identifier_from_pr_event(event: &Event) -> Option<String> {
814/// 814///
815/// # Returns 815/// # Returns
816/// A `ProcessResult` describing what was processed 816/// A `ProcessResult` describing what was processed
817#[allow(clippy::too_many_arguments)]
817pub async fn process_newly_available_git_data( 818pub async fn process_newly_available_git_data(
818 source_repo_path: &Path, 819 source_repo_path: &Path,
819 new_oids: &HashSet<String>, 820 new_oids: &HashSet<String>,
@@ -1339,6 +1340,7 @@ async fn process_purgatory_pr_events(
1339/// When `write_policy` and `rejected_events_index` are provided (git push path), 1340/// When `write_policy` and `rejected_events_index` are provided (git push path),
1340/// any maintainer announcements sitting in the hot cache are re-processed immediately 1341/// any maintainer announcements sitting in the hot cache are re-processed immediately
1341/// after the owner announcement is promoted, so they don't wait for the next sync cycle. 1342/// after the owner announcement is promoted, so they don't wait for the next sync cycle.
1343#[allow(clippy::too_many_arguments)]
1342async fn process_purgatory_announcements( 1344async fn process_purgatory_announcements(
1343 identifier: &str, 1345 identifier: &str,
1344 source_repo_path: &Path, 1346 source_repo_path: &Path,
diff --git a/src/http/mod.rs b/src/http/mod.rs
index 76ffef3..c397365 100644
--- a/src/http/mod.rs
+++ b/src/http/mod.rs
@@ -105,6 +105,7 @@ struct HttpService {
105} 105}
106 106
107impl HttpService { 107impl HttpService {
108 #[allow(clippy::too_many_arguments)]
108 fn new( 109 fn new(
109 relay: LocalRelay, 110 relay: LocalRelay,
110 config: Config, 111 config: Config,
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs
index a0088e1..03132bf 100644
--- a/src/nostr/builder.rs
+++ b/src/nostr/builder.rs
@@ -18,7 +18,6 @@ use crate::nostr::policy::{
18 ReferenceResult, RelatedEventPolicy, StatePolicy, StateResult, 18 ReferenceResult, RelatedEventPolicy, StatePolicy, StateResult,
19}; 19};
20 20
21
22/// Type alias for the shared database used by the relay 21/// Type alias for the shared database used by the relay
23pub type SharedDatabase = Arc<dyn NostrDatabase>; 22pub type SharedDatabase = Arc<dyn NostrDatabase>;
24 23
diff --git a/src/nostr/policy/announcement.rs b/src/nostr/policy/announcement.rs
index b366f0b..aba5181 100644
--- a/src/nostr/policy/announcement.rs
+++ b/src/nostr/policy/announcement.rs
@@ -70,7 +70,10 @@ impl AnnouncementPolicy {
70 .is_some_and(|entry| event.created_at > entry.event.created_at); 70 .is_some_and(|entry| event.created_at > entry.event.created_at);
71 71
72 if should_evict { 72 if should_evict {
73 self.remove_purgatory_announcement(&event.pubkey, &announcement.identifier); 73 self.remove_purgatory_announcement(
74 &event.pubkey,
75 &announcement.identifier,
76 );
74 } 77 }
75 78
76 match self 79 match self
@@ -145,10 +148,9 @@ impl AnnouncementPolicy {
145 ); 148 );
146 AnnouncementResult::AcceptPurgatory 149 AnnouncementResult::AcceptPurgatory
147 } 150 }
148 Err(e) => AnnouncementResult::Reject(format!( 151 Err(e) => {
149 "Failed to parse announcement: {}", 152 AnnouncementResult::Reject(format!("Failed to parse announcement: {}", e))
150 e 153 }
151 )),
152 } 154 }
153 } 155 }
154 // AcceptPurgatory shouldn't come from validate_announcement, but handle it 156 // AcceptPurgatory shouldn't come from validate_announcement, but handle it
@@ -161,11 +163,7 @@ impl AnnouncementPolicy {
161 /// Called when a replacement announcement arrives for a (pubkey, identifier) pair 163 /// Called when a replacement announcement arrives for a (pubkey, identifier) pair
162 /// that is currently in purgatory. Updates the purgatory entry and extends the 164 /// that is currently in purgatory. Updates the purgatory entry and extends the
163 /// expiry so the new announcement has a fresh waiting window. 165 /// expiry so the new announcement has a fresh waiting window.
164 fn replace_purgatory_announcement( 166 fn replace_purgatory_announcement(&self, event: &Event, announcement: &RepositoryAnnouncement) {
165 &self,
166 event: &Event,
167 announcement: &RepositoryAnnouncement,
168 ) {
169 let repo_path = self.ctx.git_data_path.join(announcement.repo_path()); 167 let repo_path = self.ctx.git_data_path.join(announcement.repo_path());
170 let relays: HashSet<String> = announcement.relays.iter().cloned().collect(); 168 let relays: HashSet<String> = announcement.relays.iter().cloned().collect();
171 169
diff --git a/src/nostr/policy/deletion.rs b/src/nostr/policy/deletion.rs
index 6457c90..c5a52d4 100644
--- a/src/nostr/policy/deletion.rs
+++ b/src/nostr/policy/deletion.rs
@@ -155,7 +155,9 @@ impl DeletionPolicy {
155 author = %author.to_hex(), 155 author = %author.to_hex(),
156 "Deletion request: removing purgatory state event by event ID" 156 "Deletion request: removing purgatory state event by event ID"
157 ); 157 );
158 self.ctx.purgatory.remove_state_event(&identifier, &entry.event.id); 158 self.ctx
159 .purgatory
160 .remove_state_event(&identifier, &entry.event.id);
159 return; // event IDs are unique 161 return; // event IDs are unique
160 } 162 }
161 } 163 }
@@ -223,7 +225,9 @@ impl DeletionPolicy {
223 if entry.author == *author 225 if entry.author == *author
224 && entry.event.created_at.as_secs() <= deletion_created_at 226 && entry.event.created_at.as_secs() <= deletion_created_at
225 { 227 {
226 self.ctx.purgatory.remove_state_event(identifier, &entry.event.id); 228 self.ctx
229 .purgatory
230 .remove_state_event(identifier, &entry.event.id);
227 removed += 1; 231 removed += 1;
228 } 232 }
229 } 233 }
@@ -306,7 +310,10 @@ mod tests {
306 EventBuilder::new(Kind::GitRepoAnnouncement, "") 310 EventBuilder::new(Kind::GitRepoAnnouncement, "")
307 .tags(vec![ 311 .tags(vec![
308 Tag::identifier(identifier), 312 Tag::identifier(identifier),
309 Tag::custom(TagKind::custom("clone"), vec!["https://example.com/repo.git"]), 313 Tag::custom(
314 TagKind::custom("clone"),
315 vec!["https://example.com/repo.git"],
316 ),
310 ]) 317 ])
311 .sign_with_keys(keys) 318 .sign_with_keys(keys)
312 .unwrap() 319 .unwrap()
@@ -331,7 +338,9 @@ mod tests {
331 let announcement = make_announcement_event(&keys, identifier); 338 let announcement = make_announcement_event(&keys, identifier);
332 add_to_purgatory(&ctx, &announcement, identifier); 339 add_to_purgatory(&ctx, &announcement, identifier);
333 340
334 assert!(ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier)); 341 assert!(ctx
342 .purgatory
343 .has_purgatory_announcement(&keys.public_key(), identifier));
335 344
336 // Build kind 5 deletion event referencing the announcement by event ID 345 // Build kind 5 deletion event referencing the announcement by event ID
337 let deletion = EventBuilder::new(Kind::EventDeletion, "") 346 let deletion = EventBuilder::new(Kind::EventDeletion, "")
@@ -347,7 +356,8 @@ mod tests {
347 356
348 assert!(matches!(result, WritePolicyResult::Accept)); 357 assert!(matches!(result, WritePolicyResult::Accept));
349 assert!( 358 assert!(
350 !ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier), 359 !ctx.purgatory
360 .has_purgatory_announcement(&keys.public_key(), identifier),
351 "Purgatory entry should have been removed" 361 "Purgatory entry should have been removed"
352 ); 362 );
353 } 363 }
@@ -361,7 +371,9 @@ mod tests {
361 let announcement = make_announcement_event(&keys, identifier); 371 let announcement = make_announcement_event(&keys, identifier);
362 add_to_purgatory(&ctx, &announcement, identifier); 372 add_to_purgatory(&ctx, &announcement, identifier);
363 373
364 assert!(ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier)); 374 assert!(ctx
375 .purgatory
376 .has_purgatory_announcement(&keys.public_key(), identifier));
365 377
366 // Build kind 5 deletion event referencing the announcement by coordinate 378 // Build kind 5 deletion event referencing the announcement by coordinate
367 let coord = format!("30617:{}:{}", keys.public_key().to_hex(), identifier); 379 let coord = format!("30617:{}:{}", keys.public_key().to_hex(), identifier);
@@ -378,7 +390,8 @@ mod tests {
378 390
379 assert!(matches!(result, WritePolicyResult::Accept)); 391 assert!(matches!(result, WritePolicyResult::Accept));
380 assert!( 392 assert!(
381 !ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier), 393 !ctx.purgatory
394 .has_purgatory_announcement(&keys.public_key(), identifier),
382 "Purgatory entry should have been removed" 395 "Purgatory entry should have been removed"
383 ); 396 );
384 } 397 }
@@ -407,7 +420,8 @@ mod tests {
407 420
408 assert!(matches!(result, WritePolicyResult::Accept)); 421 assert!(matches!(result, WritePolicyResult::Accept));
409 assert!( 422 assert!(
410 ctx.purgatory.has_purgatory_announcement(&owner_keys.public_key(), identifier), 423 ctx.purgatory
424 .has_purgatory_announcement(&owner_keys.public_key(), identifier),
411 "Purgatory entry should NOT have been removed by wrong author" 425 "Purgatory entry should NOT have been removed by wrong author"
412 ); 426 );
413 } 427 }
@@ -438,7 +452,8 @@ mod tests {
438 452
439 assert!(matches!(result, WritePolicyResult::Accept)); 453 assert!(matches!(result, WritePolicyResult::Accept));
440 assert!( 454 assert!(
441 ctx.purgatory.has_purgatory_announcement(&owner_keys.public_key(), identifier), 455 ctx.purgatory
456 .has_purgatory_announcement(&owner_keys.public_key(), identifier),
442 "Purgatory entry should NOT have been removed by wrong author" 457 "Purgatory entry should NOT have been removed by wrong author"
443 ); 458 );
444 } 459 }
@@ -450,11 +465,10 @@ mod tests {
450 465
451 // No purgatory entry exists — deletion should still be accepted 466 // No purgatory entry exists — deletion should still be accepted
452 let deletion = EventBuilder::new(Kind::EventDeletion, "") 467 let deletion = EventBuilder::new(Kind::EventDeletion, "")
453 .tags(vec![ 468 .tags(vec![Tag::custom(
454 Tag::custom(TagKind::custom("a"), vec![ 469 TagKind::custom("a"),
455 format!("30617:{}:nonexistent", keys.public_key().to_hex()) 470 vec![format!("30617:{}:nonexistent", keys.public_key().to_hex())],
456 ]), 471 )])
457 ])
458 .sign_with_keys(&keys) 472 .sign_with_keys(&keys)
459 .unwrap(); 473 .unwrap();
460 474
@@ -491,7 +505,8 @@ mod tests {
491 505
492 assert!(matches!(result, WritePolicyResult::Accept)); 506 assert!(matches!(result, WritePolicyResult::Accept));
493 assert!( 507 assert!(
494 ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier), 508 ctx.purgatory
509 .has_purgatory_announcement(&keys.public_key(), identifier),
495 "Purgatory entry should NOT be removed: entry is newer than deletion request" 510 "Purgatory entry should NOT be removed: entry is newer than deletion request"
496 ); 511 );
497 } 512 }
diff --git a/src/nostr/policy/pr_event.rs b/src/nostr/policy/pr_event.rs
index 52747a4..e4a64b8 100644
--- a/src/nostr/policy/pr_event.rs
+++ b/src/nostr/policy/pr_event.rs
@@ -7,7 +7,9 @@ use nostr_relay_builder::prelude::Event;
7 7
8use super::PolicyContext; 8use super::PolicyContext;
9use crate::git; 9use crate::git;
10use crate::git::authorization::{collect_authorized_maintainers, fetch_repository_data_excluding_purgatory}; 10use crate::git::authorization::{
11 collect_authorized_maintainers, fetch_repository_data_excluding_purgatory,
12};
11 13
12/// Policy for validating PR and PR Update events 14/// Policy for validating PR and PR Update events
13#[derive(Clone)] 15#[derive(Clone)]
@@ -131,7 +133,8 @@ impl PrEventPolicy {
131 // only be accepted for announcements that have been promoted (validated). 133 // only be accepted for announcements that have been promoted (validated).
132 // If the announcement is still in purgatory, the PR event should also go 134 // If the announcement is still in purgatory, the PR event should also go
133 // to purgatory and wait for the announcement to be promoted. 135 // to purgatory and wait for the announcement to be promoted.
134 let db_repo_data = fetch_repository_data_excluding_purgatory(&self.ctx.database, &identifier).await?; 136 let db_repo_data =
137 fetch_repository_data_excluding_purgatory(&self.ctx.database, &identifier).await?;
135 138
136 // Extract owner pubkey from source repo path 139 // Extract owner pubkey from source repo path
137 let owner_pubkey = crate::git::sync::extract_owner_from_repo_path( 140 let owner_pubkey = crate::git::sync::extract_owner_from_repo_path(
@@ -211,7 +214,8 @@ impl PrEventPolicy {
211 // only be accepted for announcements that have been promoted (validated). 214 // only be accepted for announcements that have been promoted (validated).
212 // If the announcement is still in purgatory, the PR event should also go 215 // If the announcement is still in purgatory, the PR event should also go
213 // to purgatory and wait for the announcement to be promoted. 216 // to purgatory and wait for the announcement to be promoted.
214 let db_repo_data = fetch_repository_data_excluding_purgatory(&self.ctx.database, identifier).await?; 217 let db_repo_data =
218 fetch_repository_data_excluding_purgatory(&self.ctx.database, identifier).await?;
215 219
216 // 3. Extract list of maintainers from "a 30617:<maintainer>:<identifier>" tags 220 // 3. Extract list of maintainers from "a 30617:<maintainer>:<identifier>" tags
217 let mut maintainer_pubkeys = std::collections::HashSet::new(); 221 let mut maintainer_pubkeys = std::collections::HashSet::new();
diff --git a/src/nostr/policy/state.rs b/src/nostr/policy/state.rs
index df743ae..80fe84c 100644
--- a/src/nostr/policy/state.rs
+++ b/src/nostr/policy/state.rs
@@ -158,7 +158,11 @@ impl StatePolicy {
158 // authorized it. 158 // authorized it.
159 for owner_hex in &authorized_owners { 159 for owner_hex in &authorized_owners {
160 if let Ok(owner_pk) = nostr_sdk::PublicKey::from_hex(owner_hex) { 160 if let Ok(owner_pk) = nostr_sdk::PublicKey::from_hex(owner_hex) {
161 if self.ctx.purgatory.has_purgatory_announcement(&owner_pk, &state.identifier) { 161 if self
162 .ctx
163 .purgatory
164 .has_purgatory_announcement(&owner_pk, &state.identifier)
165 {
162 self.ctx.purgatory.extend_announcement_expiry( 166 self.ctx.purgatory.extend_announcement_expiry(
163 &owner_pk, 167 &owner_pk,
164 &state.identifier, 168 &state.identifier,
diff --git a/src/purgatory/mod.rs b/src/purgatory/mod.rs
index bb6ff54..9b370d2 100644
--- a/src/purgatory/mod.rs
+++ b/src/purgatory/mod.rs
@@ -16,8 +16,14 @@ pub mod persistence;
16pub mod sync; 16pub mod sync;
17mod types; 17mod types;
18 18
19pub use helpers::{can_apply_state, can_satisfy_state, diagnose_state_mismatch, extract_refs_from_state, get_unpushed_refs}; 19pub use helpers::{
20pub use types::{AnnouncementPurgatoryEntry, EventSource, PrPurgatoryEntry, RefPair, RefUpdate, StatePurgatoryEntry}; 20 can_apply_state, can_satisfy_state, diagnose_state_mismatch, extract_refs_from_state,
21 get_unpushed_refs,
22};
23pub use types::{
24 AnnouncementPurgatoryEntry, EventSource, PrPurgatoryEntry, RefPair, RefUpdate,
25 StatePurgatoryEntry,
26};
21 27
22use dashmap::DashMap; 28use dashmap::DashMap;
23use nostr_sdk::prelude::*; 29use nostr_sdk::prelude::*;
@@ -672,9 +678,15 @@ impl Purgatory {
672 /// 678 ///
673 /// # Returns 679 /// # Returns
674 /// The announcement entry if found, None otherwise 680 /// The announcement entry if found, None otherwise
675 pub fn find_announcement(&self, owner: &PublicKey, identifier: &str) -> Option<AnnouncementPurgatoryEntry> { 681 pub fn find_announcement(
682 &self,
683 owner: &PublicKey,
684 identifier: &str,
685 ) -> Option<AnnouncementPurgatoryEntry> {
676 let key = (*owner, identifier.to_string()); 686 let key = (*owner, identifier.to_string());
677 self.announcement_purgatory.get(&key).map(|entry| entry.clone()) 687 self.announcement_purgatory
688 .get(&key)
689 .map(|entry| entry.clone())
678 } 690 }
679 691
680 /// Get all announcements in purgatory for a given identifier. 692 /// Get all announcements in purgatory for a given identifier.
@@ -687,7 +699,10 @@ impl Purgatory {
687 /// 699 ///
688 /// # Returns 700 /// # Returns
689 /// Vector of announcement entries for this identifier 701 /// Vector of announcement entries for this identifier
690 pub fn get_announcements_by_identifier(&self, identifier: &str) -> Vec<AnnouncementPurgatoryEntry> { 702 pub fn get_announcements_by_identifier(
703 &self,
704 identifier: &str,
705 ) -> Vec<AnnouncementPurgatoryEntry> {
691 self.announcement_purgatory 706 self.announcement_purgatory
692 .iter() 707 .iter()
693 .filter(|entry| entry.key().1 == identifier) 708 .filter(|entry| entry.key().1 == identifier)
@@ -755,7 +770,12 @@ impl Purgatory {
755 /// * `owner` - The owner pubkey 770 /// * `owner` - The owner pubkey
756 /// * `identifier` - The repository identifier 771 /// * `identifier` - The repository identifier
757 /// * `duration` - Minimum duration to guarantee from now 772 /// * `duration` - Minimum duration to guarantee from now
758 pub fn extend_announcement_expiry(&self, owner: &PublicKey, identifier: &str, duration: Duration) { 773 pub fn extend_announcement_expiry(
774 &self,
775 owner: &PublicKey,
776 identifier: &str,
777 duration: Duration,
778 ) {
759 let key = (*owner, identifier.to_string()); 779 let key = (*owner, identifier.to_string());
760 780
761 // Collect revival info before taking a mutable borrow 781 // Collect revival info before taking a mutable borrow
@@ -977,16 +997,24 @@ impl Purgatory {
977 .map(|entry| { 997 .map(|entry| {
978 let key = entry.key(); 998 let key = entry.key();
979 let v = entry.value(); 999 let v = entry.value();
980 (key.0.clone(), key.1.clone(), v.repo_path.clone(), v.event.id, v.soft_expired) 1000 (
1001 key.0,
1002 key.1.clone(),
1003 v.repo_path.clone(),
1004 v.event.id,
1005 v.soft_expired,
1006 )
981 }) 1007 })
982 .collect(); 1008 .collect();
983 1009
984 let mut announcement_removed = 0; 1010 let mut announcement_removed = 0;
985 for (owner, identifier, repo_path, event_id, already_soft_expired) in expired_announcements { 1011 for (owner, identifier, repo_path, event_id, already_soft_expired) in expired_announcements
1012 {
986 if already_soft_expired { 1013 if already_soft_expired {
987 // Phase 2: fully remove 1014 // Phase 2: fully remove
988 self.mark_expired(event_id); 1015 self.mark_expired(event_id);
989 self.announcement_purgatory.remove(&(owner.clone(), identifier.clone())); 1016 self.announcement_purgatory
1017 .remove(&(owner, identifier.clone()));
990 announcement_removed += 1; 1018 announcement_removed += 1;
991 tracing::info!( 1019 tracing::info!(
992 owner = %owner, 1020 owner = %owner,
@@ -1026,7 +1054,10 @@ impl Purgatory {
1026 1054
1027 if repo_gone { 1055 if repo_gone {
1028 // Mark soft_expired and extend expiry 1056 // Mark soft_expired and extend expiry
1029 if let Some(mut entry) = self.announcement_purgatory.get_mut(&(owner.clone(), identifier.clone())) { 1057 if let Some(mut entry) = self
1058 .announcement_purgatory
1059 .get_mut(&(owner, identifier.clone()))
1060 {
1030 entry.soft_expired = true; 1061 entry.soft_expired = true;
1031 entry.expires_at = now + SOFT_EXPIRY_EXTENDED; 1062 entry.expires_at = now + SOFT_EXPIRY_EXTENDED;
1032 } 1063 }
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
index cd62380..36142e3 100644
--- a/src/sync/mod.rs
+++ b/src/sync/mod.rs
@@ -2406,7 +2406,8 @@ impl SyncManager {
2406 } 2406 }
2407 2407
2408 // Register any new entries in repo_sync_index as StateOnly 2408 // Register any new entries in repo_sync_index as StateOnly
2409 let mut new_relay_urls: std::collections::HashSet<String> = std::collections::HashSet::new(); 2409 let mut new_relay_urls: std::collections::HashSet<String> =
2410 std::collections::HashSet::new();
2410 { 2411 {
2411 let mut index = self.repo_sync_index.write().await; 2412 let mut index = self.repo_sync_index.write().await;
2412 for (repo_id, relays) in &announcements { 2413 for (repo_id, relays) in &announcements {