mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
Add rustfmt.toml with stable defaults and apply cargo fmt to all source files. This establishes a consistent formatting baseline for CI enforcement.
298 lines
9.5 KiB
Rust
298 lines
9.5 KiB
Rust
use ratatui::Frame;
|
|
use ratatui::layout::{Constraint, Layout, Rect};
|
|
use ratatui::style::{Color, Style};
|
|
use ratatui::text::Line;
|
|
use ratatui::widgets::{Block, Borders, Paragraph};
|
|
|
|
use crate::app::{App, Tab};
|
|
|
|
use super::helpers;
|
|
|
|
pub fn draw(frame: &mut Frame, app: &App, area: Rect) {
|
|
let data = match app.data.get(&Tab::Routing) {
|
|
Some(d) => d,
|
|
None => {
|
|
let msg =
|
|
Paragraph::new(" Waiting for data...").style(Style::default().fg(Color::DarkGray));
|
|
frame.render_widget(msg, area);
|
|
return;
|
|
}
|
|
};
|
|
|
|
let chunks = Layout::vertical([
|
|
Constraint::Length(7), // Routing State
|
|
Constraint::Length(8), // Coordinate Cache
|
|
Constraint::Min(3), // Routing Statistics
|
|
])
|
|
.split(area);
|
|
|
|
draw_routing_state(frame, data, chunks[0]);
|
|
draw_coord_cache(frame, app, chunks[1]);
|
|
draw_routing_stats(frame, data, chunks[2]);
|
|
}
|
|
|
|
fn draw_routing_state(frame: &mut Frame, data: &serde_json::Value, area: Rect) {
|
|
let lines = vec![
|
|
helpers::kv_line(
|
|
"Coord Cache",
|
|
&helpers::u64_field(data, "coord_cache_entries"),
|
|
),
|
|
helpers::kv_line(
|
|
"Identity Cache",
|
|
&helpers::u64_field(data, "identity_cache_entries"),
|
|
),
|
|
helpers::kv_line(
|
|
"Pending Lookups",
|
|
&helpers::u64_field(data, "pending_lookups"),
|
|
),
|
|
helpers::kv_line(
|
|
"Recent Requests",
|
|
&helpers::u64_field(data, "recent_requests"),
|
|
),
|
|
];
|
|
|
|
let block = Block::default()
|
|
.borders(Borders::ALL)
|
|
.title(" Routing State ");
|
|
let inner = block.inner(area);
|
|
frame.render_widget(block, area);
|
|
frame.render_widget(Paragraph::new(lines), inner);
|
|
}
|
|
|
|
/// Format a forwarding counter as "N pkts (formatted_bytes)".
|
|
fn fwd_line(data: &serde_json::Value, label: &str, pkt_key: &str, byte_key: &str) -> Line<'static> {
|
|
let pkts = data
|
|
.get("forwarding")
|
|
.and_then(|f| f.get(pkt_key))
|
|
.and_then(|v| v.as_u64())
|
|
.unwrap_or(0);
|
|
let bytes = data
|
|
.get("forwarding")
|
|
.and_then(|f| f.get(byte_key))
|
|
.and_then(|v| v.as_u64())
|
|
.unwrap_or(0);
|
|
helpers::kv_line(
|
|
label,
|
|
&format!("{} pkts ({})", pkts, helpers::format_bytes(bytes)),
|
|
)
|
|
}
|
|
|
|
fn draw_routing_stats(frame: &mut Frame, data: &serde_json::Value, area: Rect) {
|
|
let block = Block::default()
|
|
.borders(Borders::ALL)
|
|
.title(" Routing Statistics ");
|
|
let inner = block.inner(area);
|
|
frame.render_widget(block, area);
|
|
|
|
let cols =
|
|
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]).split(inner);
|
|
|
|
// Left column: Forwarding + Discovery
|
|
let mut left = vec![
|
|
helpers::section_header("Forwarding"),
|
|
fwd_line(data, "Received", "received_packets", "received_bytes"),
|
|
fwd_line(data, "Delivered", "delivered_packets", "delivered_bytes"),
|
|
fwd_line(data, "Forwarded", "forwarded_packets", "forwarded_bytes"),
|
|
fwd_line(data, "Originated", "originated_packets", "originated_bytes"),
|
|
fwd_line(
|
|
data,
|
|
"Decode Error",
|
|
"decode_error_packets",
|
|
"decode_error_bytes",
|
|
),
|
|
fwd_line(
|
|
data,
|
|
"TTL Exhausted",
|
|
"ttl_exhausted_packets",
|
|
"ttl_exhausted_bytes",
|
|
),
|
|
fwd_line(
|
|
data,
|
|
"No Route",
|
|
"drop_no_route_packets",
|
|
"drop_no_route_bytes",
|
|
),
|
|
fwd_line(
|
|
data,
|
|
"MTU Exceeded",
|
|
"drop_mtu_exceeded_packets",
|
|
"drop_mtu_exceeded_bytes",
|
|
),
|
|
fwd_line(
|
|
data,
|
|
"Send Error",
|
|
"drop_send_error_packets",
|
|
"drop_send_error_bytes",
|
|
),
|
|
Line::from(""),
|
|
helpers::section_header("Discovery Requests"),
|
|
helpers::kv_line(
|
|
"Received",
|
|
&helpers::nested_u64(data, "discovery", "req_received"),
|
|
),
|
|
helpers::kv_line(
|
|
"Forwarded",
|
|
&helpers::nested_u64(data, "discovery", "req_forwarded"),
|
|
),
|
|
helpers::kv_line(
|
|
"Initiated",
|
|
&helpers::nested_u64(data, "discovery", "req_initiated"),
|
|
),
|
|
helpers::kv_line(
|
|
"Deduplicated",
|
|
&helpers::nested_u64(data, "discovery", "req_deduplicated"),
|
|
),
|
|
helpers::kv_line(
|
|
"Target Is Us",
|
|
&helpers::nested_u64(data, "discovery", "req_target_is_us"),
|
|
),
|
|
helpers::kv_line(
|
|
"Duplicate",
|
|
&helpers::nested_u64(data, "discovery", "req_duplicate"),
|
|
),
|
|
helpers::kv_line(
|
|
"Bloom Miss",
|
|
&helpers::nested_u64(data, "discovery", "req_bloom_miss"),
|
|
),
|
|
helpers::kv_line(
|
|
"Backoff Suppressed",
|
|
&helpers::nested_u64(data, "discovery", "req_backoff_suppressed"),
|
|
),
|
|
helpers::kv_line(
|
|
"Fwd Rate Limited",
|
|
&helpers::nested_u64(data, "discovery", "req_forward_rate_limited"),
|
|
),
|
|
helpers::kv_line(
|
|
"TTL Exhausted",
|
|
&helpers::nested_u64(data, "discovery", "req_ttl_exhausted"),
|
|
),
|
|
helpers::kv_line(
|
|
"Decode Error",
|
|
&helpers::nested_u64(data, "discovery", "req_decode_error"),
|
|
),
|
|
Line::from(""),
|
|
helpers::section_header("Discovery Responses"),
|
|
helpers::kv_line(
|
|
"Received",
|
|
&helpers::nested_u64(data, "discovery", "resp_received"),
|
|
),
|
|
helpers::kv_line(
|
|
"Accepted",
|
|
&helpers::nested_u64(data, "discovery", "resp_accepted"),
|
|
),
|
|
helpers::kv_line(
|
|
"Forwarded",
|
|
&helpers::nested_u64(data, "discovery", "resp_forwarded"),
|
|
),
|
|
helpers::kv_line(
|
|
"Timed Out",
|
|
&helpers::nested_u64(data, "discovery", "resp_timed_out"),
|
|
),
|
|
helpers::kv_line(
|
|
"Identity Miss",
|
|
&helpers::nested_u64(data, "discovery", "resp_identity_miss"),
|
|
),
|
|
helpers::kv_line(
|
|
"Proof Failed",
|
|
&helpers::nested_u64(data, "discovery", "resp_proof_failed"),
|
|
),
|
|
helpers::kv_line(
|
|
"Decode Error",
|
|
&helpers::nested_u64(data, "discovery", "resp_decode_error"),
|
|
),
|
|
];
|
|
|
|
// Right column: Error Signals + Congestion
|
|
let mut right = vec![
|
|
helpers::section_header("Error Signals"),
|
|
helpers::kv_line(
|
|
"Coords Required",
|
|
&helpers::nested_u64(data, "error_signals", "coords_required"),
|
|
),
|
|
helpers::kv_line(
|
|
"Path Broken",
|
|
&helpers::nested_u64(data, "error_signals", "path_broken"),
|
|
),
|
|
helpers::kv_line(
|
|
"MTU Exceeded",
|
|
&helpers::nested_u64(data, "error_signals", "mtu_exceeded"),
|
|
),
|
|
Line::from(""),
|
|
helpers::section_header("Congestion"),
|
|
helpers::kv_line(
|
|
"CE Forwarded",
|
|
&helpers::nested_u64(data, "congestion", "ce_forwarded"),
|
|
),
|
|
helpers::kv_line(
|
|
"CE Received",
|
|
&helpers::nested_u64(data, "congestion", "ce_received"),
|
|
),
|
|
helpers::kv_line(
|
|
"Congestion Detected",
|
|
&helpers::nested_u64(data, "congestion", "congestion_detected"),
|
|
),
|
|
helpers::kv_line(
|
|
"Kernel Drops",
|
|
&helpers::nested_u64(data, "congestion", "kernel_drop_events"),
|
|
),
|
|
];
|
|
|
|
let max_lines = cols[0].height as usize;
|
|
left.truncate(max_lines);
|
|
right.truncate(max_lines);
|
|
|
|
frame.render_widget(Paragraph::new(left), cols[0]);
|
|
frame.render_widget(Paragraph::new(right), cols[1]);
|
|
}
|
|
|
|
fn draw_coord_cache(frame: &mut Frame, app: &App, area: Rect) {
|
|
let data = match app.data.get(&Tab::Cache) {
|
|
Some(d) => d,
|
|
None => {
|
|
let block = Block::default()
|
|
.borders(Borders::ALL)
|
|
.title(" Coordinate Cache ");
|
|
let inner = block.inner(area);
|
|
frame.render_widget(block, area);
|
|
let msg =
|
|
Paragraph::new(" Waiting for data...").style(Style::default().fg(Color::DarkGray));
|
|
frame.render_widget(msg, inner);
|
|
return;
|
|
}
|
|
};
|
|
|
|
let entries = helpers::u64_field(data, "entries");
|
|
let max_entries = helpers::u64_field(data, "max_entries");
|
|
let fill_pct = data
|
|
.get("fill_ratio")
|
|
.and_then(|v| v.as_f64())
|
|
.map(|r| format!("{:.1}%", r * 100.0))
|
|
.unwrap_or_else(|| "-".into());
|
|
let ttl = data
|
|
.get("default_ttl_ms")
|
|
.and_then(|v| v.as_u64())
|
|
.map(helpers::format_duration_ms)
|
|
.unwrap_or_else(|| "-".into());
|
|
let expired = helpers::u64_field(data, "expired");
|
|
let avg_age = data
|
|
.get("avg_age_ms")
|
|
.and_then(|v| v.as_u64())
|
|
.map(helpers::format_duration_ms)
|
|
.unwrap_or_else(|| "-".into());
|
|
|
|
let lines = vec![
|
|
helpers::kv_line("Entries", &format!("{entries} / {max_entries}")),
|
|
helpers::kv_line("Fill Ratio", &fill_pct),
|
|
helpers::kv_line("Default TTL", &ttl),
|
|
helpers::kv_line("Expired", &expired),
|
|
helpers::kv_line("Avg Age", &avg_age),
|
|
];
|
|
|
|
let block = Block::default()
|
|
.borders(Borders::ALL)
|
|
.title(" Coordinate Cache ");
|
|
let inner = block.inner(area);
|
|
frame.render_widget(block, area);
|
|
frame.render_widget(Paragraph::new(lines), inner);
|
|
}
|