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:
Diffstat (limited to 'src/sync/mod.rs')
-rw-r--r--src/sync/mod.rs125
1 files changed, 124 insertions, 1 deletions
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
index a3189a3..108ebe9 100644
--- a/src/sync/mod.rs
+++ b/src/sync/mod.rs
@@ -407,6 +407,32 @@ async fn run_daily_timer(sync_manager: Arc<Mutex<SyncManager>>) {
407 } 407 }
408} 408}
409 409
410// =============================================================================
411// Disconnect Checker (Phase 8)
412// =============================================================================
413
414/// Check interval for empty relay cleanup in seconds
415const DISCONNECT_CHECK_INTERVAL_SECS: u64 = 60;
416
417/// Run the disconnect checker for periodic cleanup of empty relays
418///
419/// This function runs in a loop, checking every 60 seconds for relays
420/// that have no repos or root events to sync. Non-bootstrap relays
421/// that are empty will be disconnected to free up resources.
422///
423/// Bootstrap relays are never disconnected, even if empty.
424async fn run_disconnect_checker(sync_manager: Arc<Mutex<SyncManager>>) {
425 loop {
426 // Check every 60 seconds
427 tokio::time::sleep(Duration::from_secs(DISCONNECT_CHECK_INTERVAL_SECS)).await;
428
429 tracing::debug!("Disconnect checker running");
430
431 let mut manager = sync_manager.lock().await;
432 manager.check_disconnects().await;
433 }
434}
435
410/// Manages proactive synchronization with external relays 436/// Manages proactive synchronization with external relays
411/// 437///
412/// The SyncManager runs as a background task, subscribing to repository 438/// The SyncManager runs as a background task, subscribing to repository
@@ -693,7 +719,13 @@ impl SyncManager {
693 run_daily_timer(timer_manager).await; 719 run_daily_timer(timer_manager).await;
694 }); 720 });
695 721
696 // 9. Main loop - handle actions from self-subscriber, disconnect, EOSE, and connect notifications 722 // 9. Spawn disconnect checker task
723 let checker_manager = Arc::clone(&sync_manager);
724 tokio::spawn(async move {
725 run_disconnect_checker(checker_manager).await;
726 });
727
728 // 10. Main loop - handle actions from self-subscriber, disconnect, EOSE, and connect notifications
697 loop { 729 loop {
698 // Wait for an event without holding the lock 730 // Wait for an event without holding the lock
699 tokio::select! { 731 tokio::select! {
@@ -1566,4 +1598,95 @@ impl SyncManager {
1566 1598
1567 Ok(()) 1599 Ok(())
1568 } 1600 }
1601
1602 /// Check for relays that should be disconnected
1603 ///
1604 /// This method is called periodically by run_disconnect_checker.
1605 /// It identifies non-bootstrap relays that have no repos or root events
1606 /// to sync and disconnects them to free up resources.
1607 ///
1608 /// Bootstrap relays are NEVER disconnected, even if empty.
1609 async fn check_disconnects(&mut self) {
1610 // Collect relays to disconnect
1611 let to_disconnect: Vec<String> = {
1612 let index = self.relay_sync_index.read().await;
1613 index
1614 .iter()
1615 .filter_map(|(relay_url, state)| {
1616 // Skip bootstrap relays - they stay connected
1617 if state.is_bootstrap {
1618 return None;
1619 }
1620
1621 // Disconnect if no repos and no root events
1622 if state.repos.is_empty() && state.root_events.is_empty() {
1623 Some(relay_url.clone())
1624 } else {
1625 None
1626 }
1627 })
1628 .collect()
1629 };
1630
1631 if to_disconnect.is_empty() {
1632 tracing::trace!("No empty relays to disconnect");
1633 return;
1634 }
1635
1636 tracing::info!(
1637 count = to_disconnect.len(),
1638 relays = ?to_disconnect,
1639 "Found empty non-bootstrap relays to disconnect"
1640 );
1641
1642 // Disconnect empty relays
1643 for relay_url in to_disconnect {
1644 self.disconnect_relay(&relay_url).await;
1645 }
1646 }
1647
1648 /// Disconnect a relay and clean up all associated state
1649 ///
1650 /// This method:
1651 /// - Removes the relay from relay_sync_index
1652 /// - Removes the relay from pending_sync_index
1653 /// - Disconnects the connection if it exists
1654 ///
1655 /// Used by check_disconnects for cleanup of empty relays.
1656 async fn disconnect_relay(&mut self, relay_url: &str) {
1657 tracing::info!(relay = %relay_url, "Disconnecting empty relay");
1658
1659 // Remove from relay_sync_index
1660 {
1661 let mut index = self.relay_sync_index.write().await;
1662 if index.remove(relay_url).is_some() {
1663 tracing::debug!(
1664 relay = %relay_url,
1665 "Removed relay from relay_sync_index"
1666 );
1667 }
1668 }
1669
1670 // Remove from pending_sync_index
1671 {
1672 let mut pending = self.pending_sync_index.write().await;
1673 if pending.remove(relay_url).is_some() {
1674 tracing::debug!(
1675 relay = %relay_url,
1676 "Removed relay from pending_sync_index"
1677 );
1678 }
1679 }
1680
1681 // Disconnect the connection if it exists
1682 if let Some(connection) = self.connections.remove(relay_url) {
1683 connection.disconnect().await;
1684 tracing::debug!(
1685 relay = %relay_url,
1686 "Disconnected connection"
1687 );
1688 }
1689
1690 tracing::info!(relay = %relay_url, "Relay disconnected and cleaned up");
1691 }
1569} \ No newline at end of file 1692} \ No newline at end of file