Repository: fujiapple852/trippy (language: rust)

Issue:
Add src and dest port custom columns
add the src and dest ports (for UDP and TCP modes) as custom columns.




Discussion / hints:

Fix patch:
diff --git a/src/backend/trace.rs b/src/backend/trace.rs
index cd659f977..8e91a61ed 100644
--- a/src/backend/trace.rs
+++ b/src/backend/trace.rs
@@ -147,6 +147,10 @@ pub struct Hop {
     jmax: Option<Duration>,
     /// The smoothed jitter value for all probes at this hop.
     jinta: f64,
+    /// The source port for last probe for this hop.
+    last_src_port: u16,
+    /// The destination port for last probe for this hop.
+    last_dest_port: u16,
     /// The history of round trip times across the last N rounds.
     samples: Vec<Duration>,
     /// The ICMP extensions for this hop.
@@ -242,11 +246,20 @@ impl Hop {
     pub fn javg_ms(&self) -> f64 {
         self.javg
     }
+
     /// The jitter interval of all probes.
     pub fn jinta(&self) -> f64 {
         self.jinta
     }
 
+    pub fn last_src_port(&self) -> u16 {
+        self.last_src_port
+    }
+
+    pub fn last_dest_port(&self) -> u16 {
+        self.last_dest_port
+    }
+
     /// The last N samples.
     pub fn samples(&self) -> &[Duration] {
         &self.samples
@@ -272,6 +285,8 @@ impl Default for Hop {
             javg: 0f64,
             jmax: None,
             jinta: 0f64,
+            last_src_port: 0_u16,
+            last_dest_port: 0_u16,
             mean: 0f64,
             m2: 0f64,
             samples: Vec::default(),
@@ -394,6 +409,8 @@ impl TraceData {
                 let host = complete.host;
                 *hop.addrs.entry(host).or_default() += 1;
                 hop.extensions = complete.extensions.clone();
+                hop.last_src_port = complete.src_port.0;
+                hop.last_dest_port = complete.dest_port.0;
             }
             ProbeState::Awaited(awaited) => {
                 self.update_lowest_ttl(awaited.ttl);
@@ -405,6 +422,8 @@ impl TraceData {
                 if self.hops[index].samples.len() > self.max_samples {
                     self.hops[index].samples.pop();
                 }
+                self.hops[index].last_src_port = awaited.src_port.0;
+                self.hops[index].last_dest_port = awaited.dest_port.0;
             }
             ProbeState::NotSent | ProbeState::Skipped => {}
         }
diff --git a/src/config/columns.rs b/src/config/columns.rs
index 0a3948253..4c24e12c1 100644
--- a/src/config/columns.rs
+++ b/src/config/columns.rs
@@ -79,6 +79,10 @@ pub enum TuiColumn {
     Jmax,
     /// The smoothed jitter value for all probes at this hop.
     Jinta,
+    /// The source port for last probe for this hop.
+    LastSrcPort,
+    /// The destination port for last probe for this hop.
+    LastDestPort,
 }
 
 impl TryFrom<char> for TuiColumn {
@@ -101,6 +105,8 @@ impl TryFrom<char> for TuiColumn {
             'g' => Ok(Self::Javg),
             'x' => Ok(Self::Jmax),
             'i' => Ok(Self::Jinta),
+            'S' => Ok(Self::LastSrcPort),
+            'P' => Ok(Self::LastDestPort),
             c => Err(anyhow!(format!("unknown column code: {c}"))),
         }
     }
@@ -124,6 +130,8 @@ impl Display for TuiColumn {
             Self::Javg => write!(f, "g"),
             Self::Jmax => write!(f, "x"),
             Self::Jinta => write!(f, "i"),
+            Self::LastSrcPort => write!(f, "S"),
+            Self::LastDestPort => write!(f, "P"),
         }
     }
 }
diff --git a/src/frontend/columns.rs b/src/frontend/columns.rs
index b33c2d6f9..56b44bf4f 100644
--- a/src/frontend/columns.rs
+++ b/src/frontend/columns.rs
@@ -87,6 +87,10 @@ pub enum Column {
     Jmax,
     /// The smoothed jitter value for all probes at this hop.
     Jinta,
+    /// The source port for last probe for this hop.
+    LastSrcPort,
+    /// The destination port for last probe for this hop.
+    LastDestPort,
 }
 
 impl From<Column> for char {
@@ -107,6 +111,8 @@ impl From<Column> for char {
             Column::Javg => 'g',
             Column::Jmax => 'x',
             Column::Jinta => 'i',
+            Column::LastSrcPort => 'S',
+            Column::LastDestPort => 'P',
         }
     }
 }
@@ -129,6 +135,8 @@ impl From<TuiColumn> for Column {
             TuiColumn::Javg => Self::Javg,
             TuiColumn::Jmax => Self::Jmax,
             TuiColumn::Jinta => Self::Jinta,
+            TuiColumn::LastSrcPort => Self::LastSrcPort,
+            TuiColumn::LastDestPort => Self::LastDestPort,
         }
     }
 }
@@ -151,6 +159,8 @@ impl Display for Column {
             Self::Javg => write!(f, "Javg"),
             Self::Jmax => write!(f, "Jmax"),
             Self::Jinta => write!(f, "Jint"),
+            Self::LastSrcPort => write!(f, "Sprt"),
+            Self::LastDestPort => write!(f, "Dprt"),
         }
     }
 }
@@ -175,6 +185,8 @@ impl Column {
             Self::Javg => ColumnWidth::Fixed(7),
             Self::Jmax => ColumnWidth::Fixed(7),
             Self::Jinta => ColumnWidth::Fixed(8),
+            Self::LastSrcPort => ColumnWidth::Fixed(7),
+            Self::LastDestPort => ColumnWidth::Fixed(7),
         }
     }
 }
diff --git a/src/frontend/render/table.rs b/src/frontend/render/table.rs
index af53576b5..af394dba3 100644
--- a/src/frontend/render/table.rs
+++ b/src/frontend/render/table.rs
@@ -161,6 +161,8 @@ fn new_cell(
         Column::Javg => render_float_cell(Some(hop.javg_ms()), 1),
         Column::Jmax => render_float_cell(hop.jmax_ms(), 1),
         Column::Jinta => render_float_cell(Some(hop.jinta()), 1),
+        Column::LastSrcPort => render_port_cell(hop.last_src_port()),
+        Column::LastDestPort => render_port_cell(hop.last_dest_port()),
     }
 }
 
@@ -203,6 +205,14 @@ fn render_status_cell(hop: &Hop, is_target: bool) -> Cell<'static> {
     })
 }
 
+fn render_port_cell(port: u16) -> Cell<'static> {
+    if port > 0 {
+        Cell::from(format!("{port}"))
+    } else {
+        Cell::from("n/a")
+    }
+}
+
 /// Render hostname table cell (normal mode).
 fn render_hostname(
     app: &TuiApp,


Test patch: