Skip to main content

batman_robin/cli/
originators.rs

1use crate::Originator;
2
3use clap::Command;
4use comfy_table::presets::UTF8_FULL;
5use comfy_table::{Cell, CellAlignment, ContentArrangement, Table};
6
7/// Creates the CLI command for displaying the originator table.
8///
9/// # Returns
10/// - A `clap::Command` configured with:
11///   - Name: `"originators"`
12///   - Alias: `"o"`
13///   - Short and long description: `"Display the originator table."`
14///   - Usage override:
15///       ```text
16///       robctl [options] originators|o [options]
17///       ```
18///   - Version flag disabled
19pub fn cmd_originators() -> Command {
20    Command::new("originators")
21        .alias("o")
22        .about("Display the originator table.")
23        .long_about("Display the originator table.")
24        .override_usage("\trobctl [options] originators|o [options]\n")
25        .disable_version_flag(true)
26}
27
28/// Prints a formatted originator table.
29///
30/// # Arguments
31/// - `entries`: Slice of `Originator` entries.
32/// - `algo_name`: Name of the routing algorithm (BATMAN_IV or BATMAN_V).
33///
34/// # Behavior
35/// - For BATMAN_IV:
36///     - Columns: `"Originator"`, `"Last seen"`, `"TQ"`, `"Next hop"`, `"Outgoing IF"`
37///     - TQ is displayed as `value/255`
38/// - For BATMAN_V:
39///     - Columns: `"Originator"`, `"Last seen"`, `"Throughput (Mbit/s)"`, `"Next hop"`, `"Outgoing IF"`
40///     - Throughput is converted from kbit/s to Mbit with one decimal place
41/// - Marks best originators with a `*` prefix.
42/// - `last_seen_ms` is formatted as seconds with milliseconds precision.
43pub fn print_originators(entries: &[Originator], algo_name: &str) {
44    let mut table = Table::new();
45    table
46        .load_preset(UTF8_FULL)
47        .set_content_arrangement(ContentArrangement::Dynamic);
48
49    match algo_name {
50        "BATMAN_IV" => {
51            table.set_header(vec![
52                Cell::new("Originator").set_alignment(CellAlignment::Center),
53                Cell::new("Last seen").set_alignment(CellAlignment::Center),
54                Cell::new("TQ").set_alignment(CellAlignment::Center),
55                Cell::new("Next hop").set_alignment(CellAlignment::Center),
56                Cell::new("Outgoing IF").set_alignment(CellAlignment::Center),
57            ]);
58        }
59        "BATMAN_V" => {
60            table.set_header(vec![
61                Cell::new("Originator").set_alignment(CellAlignment::Center),
62                Cell::new("Last seen").set_alignment(CellAlignment::Center),
63                Cell::new("Throughput (Mbit/s)").set_alignment(CellAlignment::Center),
64                Cell::new("Next hop").set_alignment(CellAlignment::Center),
65                Cell::new("Outgoing IF").set_alignment(CellAlignment::Center),
66            ]);
67        }
68        _ => return,
69    }
70
71    for o in entries {
72        let last_seen_secs = o.last_seen_ms / 1000;
73        let last_seen_msecs = o.last_seen_ms % 1000;
74        let last_seen = format!("{}.{:03}s", last_seen_secs, last_seen_msecs);
75
76        let originator_text = if o.is_best {
77            format!("* {}", o.originator)
78        } else {
79            o.originator.to_string()
80        };
81        let originator_cell = Cell::new(originator_text);
82        let next_hop_cell = Cell::new(o.next_hop.to_string());
83
84        match algo_name {
85            "BATMAN_IV" => {
86                let tq = o.tq.unwrap_or(0);
87
88                table.add_row(vec![
89                    originator_cell.set_alignment(CellAlignment::Right),
90                    Cell::new(last_seen),
91                    Cell::new(format!("{}/255", tq)),
92                    next_hop_cell,
93                    Cell::new(&o.outgoing_if),
94                ]);
95            }
96
97            "BATMAN_V" => {
98                let throughput_cell = match o.throughput {
99                    Some(kbits) => {
100                        let mbit = kbits / 1000;
101                        let rest = (kbits % 1000) / 100;
102
103                        Cell::new(format!("{mbit}.{rest}"))
104                    }
105                    None => Cell::new("-"),
106                };
107
108                table.add_row(vec![
109                    originator_cell.set_alignment(CellAlignment::Right),
110                    Cell::new(last_seen),
111                    throughput_cell,
112                    next_hop_cell,
113                    Cell::new(&o.outgoing_if),
114                ]);
115            }
116            _ => {}
117        }
118    }
119
120    println!("{table}");
121}