refactor: simplify signal handling and update TUI controls
This commit is contained in:
+20
-69
@@ -153,73 +153,6 @@ async fn download_output_dependencies(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn watch_signals(token: tokio_util::sync::CancellationToken) {
|
||||
let token_clone = token.clone();
|
||||
tokio::select! {
|
||||
biased;
|
||||
() = token_clone.cancelled() => {},
|
||||
() = async move {
|
||||
match (
|
||||
tokio::signal::unix::signal(
|
||||
tokio::signal::unix::SignalKind::interrupt(),
|
||||
),
|
||||
tokio::signal::unix::signal(
|
||||
tokio::signal::unix::SignalKind::terminate(),
|
||||
)
|
||||
) {
|
||||
(Ok(mut a), Ok(mut b)) => {
|
||||
tokio::select! {
|
||||
_ = a.recv() => {
|
||||
tracing::info!("Received SIGINT, exiting...");
|
||||
token.cancel();
|
||||
},
|
||||
_ = b.recv() => {
|
||||
tracing::info!("Received SIGTERM, exiting...");
|
||||
token.cancel();
|
||||
}
|
||||
};
|
||||
}
|
||||
(Err(e), Ok(mut s)) => {
|
||||
tracing::warn!("Failed to create SIGINT handler: {}", e);
|
||||
s.recv().await;
|
||||
tracing::info!("Received SIGTERM, exiting...");
|
||||
token.cancel();
|
||||
}
|
||||
(Ok(mut s), Err(e)) => {
|
||||
tracing::warn!("Failed to create SIGTERM handler: {}", e);
|
||||
s.recv().await;
|
||||
tracing::info!("Received SIGINT, exiting...");
|
||||
token.cancel();
|
||||
}
|
||||
(Err(e), Err(e2)) => {
|
||||
tracing::warn!("Failed to create signal handlers: {}, {}", e, e2);
|
||||
}
|
||||
}
|
||||
} => {}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
async fn watch_signals(token: tokio_util::sync::CancellationToken) {
|
||||
let token_clone = token.clone();
|
||||
tokio::select! {
|
||||
biased;
|
||||
() = token_clone.cancelled() => {},
|
||||
ctrl_c = tokio::signal::ctrl_c() => {
|
||||
match ctrl_c {
|
||||
Ok(()) => {
|
||||
tracing::info!("Received Ctrl+C, exiting...");
|
||||
token.cancel();
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("Failed to create Ctrl+C handler: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async fn main_task(
|
||||
config: Arc<config::Config>,
|
||||
token: tokio_util::sync::CancellationToken,
|
||||
@@ -285,8 +218,6 @@ async fn run_with_tui(
|
||||
let terminal_guard = tui::RatatuiRestoreGuard;
|
||||
|
||||
let token = tokio_util::sync::CancellationToken::new();
|
||||
tokio::spawn(watch_signals(token.clone()));
|
||||
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
tokio::try_join!(
|
||||
@@ -301,6 +232,26 @@ async fn run_with_tui(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tui"))]
|
||||
async fn watch_signals(token: tokio_util::sync::CancellationToken) {
|
||||
let token_clone = token.clone();
|
||||
tokio::select! {
|
||||
biased;
|
||||
() = token_clone.cancelled() => {},
|
||||
ctrl_c = tokio::signal::ctrl_c() => {
|
||||
match ctrl_c {
|
||||
Ok(()) => {
|
||||
tracing::info!("Received Ctrl+C, exiting...");
|
||||
token.cancel();
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("Failed to create Ctrl+C handler: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tui"))]
|
||||
async fn run_without_tui(
|
||||
config: Arc<config::Config>,
|
||||
|
||||
+38
-35
@@ -24,7 +24,6 @@ use crate::{
|
||||
event::{AppEvent, Event},
|
||||
ipdb,
|
||||
proxy::ProxyType,
|
||||
utils::is_docker,
|
||||
};
|
||||
|
||||
const FPS: f64 = 30.0;
|
||||
@@ -49,8 +48,7 @@ pub async fn run(
|
||||
let logger_state = TuiWidgetState::default();
|
||||
while !matches!(app_state.mode, AppMode::Quit) {
|
||||
if let Some(event) = rx.recv().await {
|
||||
if handle_event(event, &mut app_state, &token, &logger_state).await
|
||||
{
|
||||
if handle_event(event, &mut app_state, &token, &logger_state) {
|
||||
terminal
|
||||
.draw(|frame| draw(frame, &app_state, &logger_state))
|
||||
.wrap_err("failed to draw tui")?;
|
||||
@@ -70,6 +68,15 @@ pub enum AppMode {
|
||||
Quit,
|
||||
}
|
||||
|
||||
impl AppMode {
|
||||
pub const fn next(&self) -> Self {
|
||||
match self {
|
||||
Self::Running => Self::Done,
|
||||
Self::Done | Self::Quit => Self::Quit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AppState {
|
||||
pub mode: AppMode,
|
||||
@@ -148,7 +155,7 @@ fn draw(f: &mut Frame, state: &AppState, logger_state: &TuiWidgetState) {
|
||||
// Scraping and checking
|
||||
Constraint::Length(1 + (3 * 3) + 1),
|
||||
// Hotkeys
|
||||
Constraint::Length(3),
|
||||
Constraint::Length(4),
|
||||
])
|
||||
.split(outer_block.inner(f.area()));
|
||||
|
||||
@@ -270,25 +277,32 @@ fn draw(f: &mut Frame, state: &AppState, logger_state: &TuiWidgetState) {
|
||||
working_proxies_block.inner(layout[2]),
|
||||
);
|
||||
}
|
||||
let lines = vec![
|
||||
Line::from("\u{2b06}\u{fe0f} Up/PageUp/k - scroll logs up"),
|
||||
Line::from("\u{2b07}\u{fe0f} Down/PageDown/j - scroll logs down"),
|
||||
if matches!(state.mode, AppMode::Running) {
|
||||
Line::from("\u{1f6d1} ESC/q/Ctrl-C - stop")
|
||||
.style(Style::default().fg(Color::Yellow))
|
||||
|
||||
let running = matches!(state.mode, AppMode::Running);
|
||||
let mut lines = Vec::with_capacity(if running { 4 } else { 3 });
|
||||
lines.push(Line::from("\u{2b06}\u{fe0f} Up / PageUp / k - scroll logs up"));
|
||||
lines.push(Line::from(
|
||||
"\u{2b07}\u{fe0f} Down / PageDown / j - scroll logs down",
|
||||
));
|
||||
if running {
|
||||
lines.push(
|
||||
Line::from("\u{1f6d1} ESC / q - stop")
|
||||
.style(Style::default().fg(Color::Yellow)),
|
||||
);
|
||||
}
|
||||
lines.push(
|
||||
Line::from(if running {
|
||||
"\u{1f6aa} Ctrl-C - quit"
|
||||
} else {
|
||||
Line::from("\u{1f6aa} ESC/q/Ctrl-C - quit")
|
||||
.style(Style::default().fg(Color::Red))
|
||||
},
|
||||
];
|
||||
"\u{1f6aa} ESC / q / Ctrl-C - quit"
|
||||
})
|
||||
.style(Style::default().fg(Color::Red)),
|
||||
);
|
||||
|
||||
f.render_widget(Text::from(lines).centered(), outer_layout[3]);
|
||||
}
|
||||
|
||||
async fn is_interactive() -> bool {
|
||||
!is_docker().await
|
||||
}
|
||||
|
||||
async fn handle_event(
|
||||
fn handle_event(
|
||||
event: Event,
|
||||
state: &mut AppState,
|
||||
token: &tokio_util::sync::CancellationToken,
|
||||
@@ -300,21 +314,13 @@ async fn handle_event(
|
||||
match crossterm_event {
|
||||
CrosstermEvent::Key(key_event) => match key_event.code {
|
||||
KeyCode::Esc | KeyCode::Char('q' | 'Q') => {
|
||||
state.mode = if matches!(state.mode, AppMode::Running) {
|
||||
AppMode::Done
|
||||
} else {
|
||||
AppMode::Quit
|
||||
};
|
||||
state.mode = state.mode.next();
|
||||
token.cancel();
|
||||
}
|
||||
KeyCode::Char('c' | 'C')
|
||||
if key_event.modifiers == KeyModifiers::CONTROL =>
|
||||
{
|
||||
state.mode = if matches!(state.mode, AppMode::Running) {
|
||||
AppMode::Done
|
||||
} else {
|
||||
AppMode::Quit
|
||||
};
|
||||
state.mode = AppMode::Quit;
|
||||
token.cancel();
|
||||
}
|
||||
KeyCode::Up | KeyCode::PageUp | KeyCode::Char('k') => {
|
||||
@@ -382,12 +388,9 @@ async fn handle_event(
|
||||
.or_insert(1);
|
||||
}
|
||||
AppEvent::Done => {
|
||||
state.mode =
|
||||
if !token.is_cancelled() && is_interactive().await {
|
||||
AppMode::Done
|
||||
} else {
|
||||
AppMode::Quit
|
||||
};
|
||||
if matches!(state.mode, AppMode::Running) {
|
||||
state.mode = AppMode::Done;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user