@@ -92,6 +92,9 @@ pub struct NetworkNode {
9292 /// Connected peers
9393 peers : Arc < RwLock < HashSet < PeerId > > > ,
9494
95+ /// Bootstrap peers to connect to
96+ bootstrap_peers : Vec < Multiaddr > ,
97+
9598 /// Event sender
9699 event_tx : mpsc:: Sender < NetworkEvent > ,
97100
@@ -139,6 +142,7 @@ impl NetworkNode {
139142 swarm,
140143 local_peer_id,
141144 peers : Arc :: new ( RwLock :: new ( HashSet :: new ( ) ) ) ,
145+ bootstrap_peers : config. bootstrap_peers . clone ( ) ,
142146 event_tx,
143147 event_rx : Some ( event_rx) ,
144148 } )
@@ -169,12 +173,36 @@ impl NetworkNode {
169173 info ! ( "Listening on {:?}" , config. listen_addr) ;
170174
171175 // Connect to bootstrap peers
172- for addr in & config. bootstrap_peers {
176+ self . dial_bootstrap_peers ( ) ;
177+
178+ Ok ( ( ) )
179+ }
180+
181+ /// Dial all bootstrap peers
182+ pub fn dial_bootstrap_peers ( & mut self ) {
183+ for addr in self . bootstrap_peers . clone ( ) {
173184 info ! ( "Dialing bootstrap peer: {}" , addr) ;
174- self . swarm . dial ( addr. clone ( ) ) ?;
185+ if let Err ( e) = self . swarm . dial ( addr. clone ( ) ) {
186+ warn ! ( "Failed to dial bootstrap peer {}: {}" , addr, e) ;
187+ }
175188 }
189+ }
176190
177- Ok ( ( ) )
191+ /// Check if connected to any bootstrap peer
192+ pub fn has_bootstrap_connection ( & self ) -> bool {
193+ if self . bootstrap_peers . is_empty ( ) {
194+ return true ; // No bootstrap peers configured
195+ }
196+ // Check if we have any peers connected
197+ !self . peers . read ( ) . is_empty ( )
198+ }
199+
200+ /// Retry connecting to bootstrap peers if not connected
201+ pub fn retry_bootstrap_if_needed ( & mut self ) {
202+ if !self . has_bootstrap_connection ( ) {
203+ info ! ( "No peers connected, retrying bootstrap peers..." ) ;
204+ self . dial_bootstrap_peers ( ) ;
205+ }
178206 }
179207
180208 /// Broadcast a message via gossip
@@ -244,9 +272,55 @@ impl NetworkNode {
244272 }
245273
246274 /// Run the event loop (should be spawned as a task)
275+ /// Includes automatic retry of bootstrap peers every 30 seconds if not connected
247276 pub async fn run ( & mut self ) {
277+ let mut bootstrap_retry_interval = tokio:: time:: interval ( Duration :: from_secs ( 30 ) ) ;
278+ bootstrap_retry_interval. set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
279+
248280 loop {
249- self . process_next_event ( ) . await ;
281+ tokio:: select! {
282+ event = self . swarm. select_next_some( ) => {
283+ self . handle_swarm_event( event) . await ;
284+ }
285+ _ = bootstrap_retry_interval. tick( ) => {
286+ self . retry_bootstrap_if_needed( ) ;
287+ }
288+ }
289+ }
290+ }
291+
292+ /// Handle a swarm event
293+ async fn handle_swarm_event ( & mut self , event : SwarmEvent < MiniChainBehaviourEvent > ) {
294+ match event {
295+ SwarmEvent :: Behaviour ( event) => {
296+ self . handle_behaviour_event ( event) . await ;
297+ }
298+ SwarmEvent :: NewListenAddr { address, .. } => {
299+ info ! ( "Listening on {}" , address) ;
300+ }
301+ SwarmEvent :: ConnectionEstablished { peer_id, .. } => {
302+ info ! ( "Connected to peer: {}" , peer_id) ;
303+ self . peers . write ( ) . insert ( peer_id) ;
304+ let _ = self
305+ . event_tx
306+ . send ( NetworkEvent :: PeerConnected ( peer_id) )
307+ . await ;
308+ }
309+ SwarmEvent :: ConnectionClosed { peer_id, .. } => {
310+ info ! ( "Disconnected from peer: {}" , peer_id) ;
311+ self . peers . write ( ) . remove ( & peer_id) ;
312+ let _ = self
313+ . event_tx
314+ . send ( NetworkEvent :: PeerDisconnected ( peer_id) )
315+ . await ;
316+ }
317+ SwarmEvent :: IncomingConnection { .. } => { }
318+ SwarmEvent :: OutgoingConnectionError { peer_id, error, .. } => {
319+ if let Some ( peer_id) = peer_id {
320+ warn ! ( "Failed to connect to {}: {}" , peer_id, error) ;
321+ }
322+ }
323+ _ => { }
250324 }
251325 }
252326
0 commit comments