diff options
Diffstat (limited to 'src/nostr/builder.rs')
| -rw-r--r-- | src/nostr/builder.rs | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs index db2f59b..0e5c18a 100644 --- a/src/nostr/builder.rs +++ b/src/nostr/builder.rs | |||
| @@ -152,13 +152,17 @@ impl Nip34WritePolicy { | |||
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | /// Handle repository state event | 154 | /// Handle repository state event |
| 155 | async fn handle_state(&self, event: &Event) -> WritePolicyResult { | 155 | /// |
| 156 | /// # Arguments | ||
| 157 | /// * `event` - The state event to validate | ||
| 158 | /// * `is_synced` - True if this event came from proactive sync (vs user-submitted) | ||
| 159 | async fn handle_state(&self, event: &Event, is_synced: bool) -> WritePolicyResult { | ||
| 156 | let event_id_str = event.id.to_bech32().unwrap_or_else(|_| event.id.to_hex()); | 160 | let event_id_str = event.id.to_bech32().unwrap_or_else(|_| event.id.to_hex()); |
| 157 | 161 | ||
| 158 | match self.state_policy.validate(event) { | 162 | match self.state_policy.validate(event) { |
| 159 | StateResult::Accept => { | 163 | StateResult::Accept => { |
| 160 | // Process state alignment asynchronously | 164 | // Process state alignment asynchronously |
| 161 | match self.state_policy.process_state_event(event).await { | 165 | match self.state_policy.process_state_event(event, is_synced).await { |
| 162 | Ok(poilicy_result) => poilicy_result, | 166 | Ok(poilicy_result) => poilicy_result, |
| 163 | Err(e) => { | 167 | Err(e) => { |
| 164 | tracing::warn!("Failed to process state event {}: {}", event_id_str, e); | 168 | tracing::warn!("Failed to process state event {}: {}", event_id_str, e); |
| @@ -178,7 +182,11 @@ impl Nip34WritePolicy { | |||
| 178 | } | 182 | } |
| 179 | 183 | ||
| 180 | /// Handle PR or PR Update event | 184 | /// Handle PR or PR Update event |
| 181 | async fn handle_pr_event(&self, event: &Event) -> WritePolicyResult { | 185 | /// |
| 186 | /// # Arguments | ||
| 187 | /// * `event` - The PR event to validate | ||
| 188 | /// * `is_synced` - True if this event came from proactive sync (vs user-submitted) | ||
| 189 | async fn handle_pr_event(&self, event: &Event, is_synced: bool) -> WritePolicyResult { | ||
| 182 | let event_id_str = event.id.to_bech32().unwrap_or_else(|_| event.id.to_hex()); | 190 | let event_id_str = event.id.to_bech32().unwrap_or_else(|_| event.id.to_hex()); |
| 183 | 191 | ||
| 184 | // duplicate check in purgatory | 192 | // duplicate check in purgatory |
| @@ -230,6 +238,19 @@ impl Nip34WritePolicy { | |||
| 230 | // Check if git data exists (delete any incorrect commits at refs/nostr/<event-id>, copies correct data to relivant repositories) | 238 | // Check if git data exists (delete any incorrect commits at refs/nostr/<event-id>, copies correct data to relivant repositories) |
| 231 | match self.pr_event_policy.git_data_check(event).await { | 239 | match self.pr_event_policy.git_data_check(event).await { |
| 232 | Ok(false) => { | 240 | Ok(false) => { |
| 241 | // Only reject expired events if they're from sync (not user-submitted) | ||
| 242 | // User-submitted events should be allowed to retry in case git data became available | ||
| 243 | if is_synced && self.ctx.purgatory.is_expired(&event.id) { | ||
| 244 | tracing::debug!( | ||
| 245 | event_id = %event_id_str, | ||
| 246 | "PR event previously expired from purgatory (synced), rejecting to prevent re-sync loop" | ||
| 247 | ); | ||
| 248 | return WritePolicyResult::Reject { | ||
| 249 | status: false, | ||
| 250 | message: "invalid: previously expired from purgatory without git data".into(), | ||
| 251 | }; | ||
| 252 | } | ||
| 253 | |||
| 233 | // No git data exists - add to purgatory | 254 | // No git data exists - add to purgatory |
| 234 | let commit = event | 255 | let commit = event |
| 235 | .tags | 256 | .tags |
| @@ -344,13 +365,17 @@ impl WritePolicy for Nip34WritePolicy { | |||
| 344 | fn admit_event<'a>( | 365 | fn admit_event<'a>( |
| 345 | &'a self, | 366 | &'a self, |
| 346 | event: &'a nostr_relay_builder::prelude::Event, | 367 | event: &'a nostr_relay_builder::prelude::Event, |
| 347 | _addr: &'a SocketAddr, | 368 | addr: &'a SocketAddr, |
| 348 | ) -> BoxedFuture<'a, WritePolicyResult> { | 369 | ) -> BoxedFuture<'a, WritePolicyResult> { |
| 349 | Box::pin(async move { | 370 | Box::pin(async move { |
| 371 | // Detect if this is a synced event (from proactive sync) vs user-submitted | ||
| 372 | // Sync uses localhost:0 as a dummy address | ||
| 373 | let is_synced = addr.ip().is_loopback() && addr.port() == 0; | ||
| 374 | |||
| 350 | match event.kind.as_u16() { | 375 | match event.kind.as_u16() { |
| 351 | KIND_REPOSITORY_ANNOUNCEMENT => self.handle_announcement(event).await, | 376 | KIND_REPOSITORY_ANNOUNCEMENT => self.handle_announcement(event).await, |
| 352 | KIND_REPOSITORY_STATE => self.handle_state(event).await, | 377 | KIND_REPOSITORY_STATE => self.handle_state(event, is_synced).await, |
| 353 | KIND_PR | KIND_PR_UPDATE => self.handle_pr_event(event).await, | 378 | KIND_PR | KIND_PR_UPDATE => self.handle_pr_event(event, is_synced).await, |
| 354 | KIND_USER_GRASP_LIST => { | 379 | KIND_USER_GRASP_LIST => { |
| 355 | // Accept all kind 10317 (User Grasp List) events | 380 | // Accept all kind 10317 (User Grasp List) events |
| 356 | // for better GRASP repository discovery | 381 | // for better GRASP repository discovery |