use std::sync::mpsc;
use super::ctx::Notify;
use crate::app::{App, HostState, PingState, StatusCenter};
use crate::event::AppEvent;
use crate::ping;
struct PingCtx<'a> {
ping: &'a mut PingState,
hosts: &'a HostState,
status: &'a mut StatusCenter,
}
impl Notify for PingCtx<'_> {
fn status_mut(&mut self) -> &mut StatusCenter {
self.status
}
}
pub(crate) fn refresh_selected_if_stale(app: &mut App, events_tx: &mpsc::Sender<AppEvent>) {
if !app.ping.auto_ping() {
return;
}
let Some(host) = app.selected_host().cloned() else {
return;
};
let mut ctx = PingCtx {
ping: &mut app.ping,
hosts: &app.hosts_state,
status: &mut app.status_center,
};
refresh_stale(&mut ctx, &host, events_tx);
}
fn refresh_stale(
ctx: &mut PingCtx,
host: &crate::ssh_config::model::HostEntry,
events_tx: &mpsc::Sender<AppEvent>,
) {
let alias = host.alias.clone();
if !ctx.ping.is_stale(&alias) {
return;
}
let (ping_alias, hostname, port) = if !host.proxy_jump.is_empty() {
let bastion_alias = host.proxy_jump.clone();
match ctx.hosts.list().iter().find(|h| h.alias == bastion_alias) {
Some(b) if !b.hostname.is_empty() => (b.alias.clone(), b.hostname.clone(), b.port),
_ => return,
}
} else if host.hostname.is_empty() {
return;
} else {
(alias, host.hostname.clone(), host.port)
};
if matches!(
ctx.ping.status_of(&ping_alias),
Some(crate::app::PingStatus::Checking)
) {
return;
}
log::debug!(
"stale-refresh: marking {} Checking and probing {}:{}",
ping_alias,
hostname,
port
);
ctx.ping
.insert_status(ping_alias.clone(), crate::app::PingStatus::Checking);
ping::ping_host(
ping_alias,
hostname,
port,
events_tx.clone(),
ctx.ping.generation(),
);
}
pub(super) fn ping_selected_host(
app: &mut App,
events_tx: &mpsc::Sender<AppEvent>,
show_hint: bool,
) {
let Some(host) = app.selected_host().cloned() else {
return;
};
let mut ctx = PingCtx {
ping: &mut app.ping,
hosts: &app.hosts_state,
status: &mut app.status_center,
};
ping_host_now(&mut ctx, &host, events_tx, show_hint);
}
fn ping_host_now(
ctx: &mut PingCtx,
host: &crate::ssh_config::model::HostEntry,
events_tx: &mpsc::Sender<AppEvent>,
show_hint: bool,
) {
let alias = host.alias.clone();
let (ping_alias, hostname, port) = if !host.proxy_jump.is_empty() {
let bastion_alias = host.proxy_jump.clone();
if let Some(bastion) = ctx.hosts.list().iter().find(|h| h.alias == bastion_alias) {
ctx.ping
.insert_status(alias.clone(), crate::app::PingStatus::Checking);
(
bastion.alias.clone(),
bastion.hostname.clone(),
bastion.port,
)
} else {
ctx.notify_warning(crate::messages::bastion_not_found(&bastion_alias));
return;
}
} else {
(alias.clone(), host.hostname.clone(), host.port)
};
ctx.ping
.insert_status(ping_alias.clone(), crate::app::PingStatus::Checking);
if show_hint && !ctx.ping.has_pinged() {
ctx.notify(crate::messages::pinging_host(&ping_alias, true));
ctx.ping.set_has_pinged(true);
} else {
ctx.notify(crate::messages::pinging_host(&ping_alias, false));
}
ping::ping_host(
ping_alias,
hostname,
port,
events_tx.clone(),
ctx.ping.generation(),
);
}