diff --git a/src/main.rs b/src/main.rs index 9a37068..a1bff55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use donglora_bridge::{config, gossip, radio, rate_limit, router, setup, tui}; use std::sync::Arc; -use std::time::Instant; +use std::time::{Duration, Instant}; use anyhow::{Context, Result}; use clap::{Parser, Subcommand}; @@ -174,13 +174,18 @@ async fn main() -> Result<()> { } else { let terminal = tui::run(config_watch_rx, swarm.clone(), stats, log_rx, cancel.clone(), start_time); - cancel.cancel(); - swarm.shutdown().await; - info!("donglora-bridge stopped"); - + // Restore the terminal first so the user's shell reappears the moment + // they hit `q`. iroh-gossip-rendezvous needs no synchronous DHT work + // on shutdown — entries age out — so the only remaining wait is + // `endpoint.close()` flushing in-flight connections. Bound it. if let Ok(mut term) = terminal { tui::restore_terminal(&mut term); } + cancel.cancel(); + if tokio::time::timeout(Duration::from_secs(2), swarm.shutdown()).await.is_err() { + warn!("graceful shutdown timed out — exiting anyway"); + } + info!("donglora-bridge stopped"); return Ok(()); } diff --git a/src/tui.rs b/src/tui.rs index 528fd85..789079e 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -17,7 +17,7 @@ use ratatui::layout::{Alignment, Constraint, Direction, Layout, Rect}; use ratatui::style::{Color, Modifier, Style}; use ratatui::symbols; use ratatui::text::{Line, Span}; -use ratatui::widgets::{Block, Borders, Clear, Paragraph, Sparkline}; +use ratatui::widgets::{Block, Borders, Paragraph, Sparkline}; use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; @@ -173,7 +173,6 @@ pub fn run( &mut series, ); - terminal.draw(|frame| draw_shutdown_overlay(frame, frame.area()))?; Ok(terminal) } @@ -631,29 +630,6 @@ fn pad_right_align(data: &[u64], width: usize) -> Vec { padded } -// ── Shutdown overlay ───────────────────────────────────────────── - -fn draw_shutdown_overlay(frame: &mut ratatui::Frame, area: Rect) { - let dim = Paragraph::new("").style(Style::default().bg(Color::Black)); - frame.render_widget(dim, area); - - let w = 36u16; - let h = 3u16; - let x = area.x + area.width.saturating_sub(w) / 2; - let y = area.y + area.height.saturating_sub(h) / 2; - let popup = Rect::new(x, y, w.min(area.width), h.min(area.height)); - - frame.render_widget(Clear, popup); - let block = Block::default().borders(Borders::ALL).border_style(Style::default().fg(C_BORDER)); - let text = Paragraph::new(Line::from(vec![ - Span::styled(" Shutting down", Style::default().fg(C_RATE_DROP)), - Span::styled(" — updating DHT...", Style::default().fg(C_LABEL)), - ])) - .alignment(Alignment::Center) - .block(block); - frame.render_widget(text, popup); -} - // ── Shared helpers ─────────────────────────────────────────────── fn panel_block(title: &str) -> Block<'static> {