use std::net::SocketAddr;
use ratatui::Frame;
use ratatui::layout::{Constraint, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::widgets::{Block, BorderType, Borders, Cell, Paragraph, Row, Table};
use sozu_command_lib::proto::command::SocketAddress;
use super::super::app::App;
use super::super::theme::Skin;
pub fn render(f: &mut Frame<'_>, area: Rect, app: &App, skin: &Skin) {
let block = Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.title(format!(
" CERTS · refresh 30 s · {} ",
app.last_certs
.as_ref()
.map(|_| "live".to_owned())
.unwrap_or_else(|| "no snapshot yet".into())
))
.style(Style::default().fg(skin.muted));
let certs = match app.last_certs.as_ref() {
Some(c) => &c.list,
None => {
let inner = block.inner(area);
f.render_widget(block, area);
f.render_widget(
Paragraph::new(
"Polling QueryCertificatesFromTheState every 30 s. First snapshot \
lands shortly after `sozu top` starts; check the EVENTS pane (tab \
7) for CERTIFICATE_ADDED / REMOVED / REPLACED transitions in the \
meantime.",
)
.style(Style::default().fg(skin.secondary)),
inner,
);
return;
}
};
let mut rows: Vec<Row<'_>> = Vec::new();
let mut total_certs = 0u32;
for by_address in &certs.certificates {
let addr = format_socket_address(&by_address.address);
for summary in &by_address.certificate_summaries {
let fp_suffix = if summary.fingerprint.len() > 12 {
let tail = summary.fingerprint.len() - 12;
format!("…{}", &summary.fingerprint[tail..])
} else {
summary.fingerprint.to_owned()
};
rows.push(
Row::new(vec![
Cell::from(addr.to_owned()),
Cell::from(summary.domain.to_owned()),
Cell::from(fp_suffix),
])
.style(Style::default().fg(skin.secondary)),
);
total_certs += 1;
}
}
if rows.is_empty() {
let inner = block.inner(area);
f.render_widget(block, area);
f.render_widget(
Paragraph::new("No certificates loaded.").style(Style::default().fg(skin.secondary)),
inner,
);
return;
}
let header = Row::new(vec![
Cell::from(format!("address · {total_certs} cert(s)")),
Cell::from("domain (SNI)"),
Cell::from("fingerprint (suffix)"),
])
.style(
Style::default()
.fg(skin.primary)
.add_modifier(Modifier::BOLD),
);
let widths = [
Constraint::Min(28),
Constraint::Min(28),
Constraint::Length(20),
];
let table = Table::new(rows, widths).header(header).block(block);
f.render_widget(table, area);
}
fn format_socket_address(address: &SocketAddress) -> String {
SocketAddr::from(*address).to_string()
}