From 768a05c6d5d38b50c12dcad9e51b6317c548bfdf Mon Sep 17 00:00:00 2001 From: frectonz Date: Wed, 22 Jul 2026 00:22:06 +0300 Subject: [PATCH] feat: show WAN gateway, netmask, and DNS in get internet --- src/main.rs | 2 +- src/multi_get.rs | 36 ++++++++++++++++++++++++------------ src/proc_get.rs | 12 ++++++++++++ src/router.rs | 7 +++++++ src/types.rs | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index a6039e0..53d6b39 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ async fn main() -> EyreResult<()> { GetCommands::Info => router.show_multi::().await?, GetCommands::System => router.show_multi::().await?, GetCommands::Signal => router.show_signal().await?, - GetCommands::Internet => router.show_multi::().await?, + GetCommands::Internet => router.show_internet().await?, GetCommands::Device => router.show_device().await?, GetCommands::Wifi => router.show_multi::().await?, GetCommands::Devices => router.show::().await?, diff --git a/src/multi_get.rs b/src/multi_get.rs index 20aeea3..56bf2dd 100644 --- a/src/multi_get.rs +++ b/src/multi_get.rs @@ -1,4 +1,5 @@ use crate::common::*; +use crate::proc_get::WanDetails; use crate::types::*; use serde::Deserialize; @@ -166,23 +167,34 @@ impl ProcGetMulti for Internet { ]; } -impl Show for Internet { +#[derive(Debug)] +pub struct InternetReport { + pub internet: Internet, + pub wan: WanDetails, +} + +impl Show for InternetReport { fn show(&self) -> EyreResult<()> { + let internet = &self.internet; + let mut table = create_table(); table .set_header(["Internet", "Value"]) - .add_row(["Status", &self.ppp_status.to_string()]) - .add_row(["WAN IP", or_dash(&self.wan_ipaddr)]) - .add_row(["LAN Domain", &self.lan_domain]) - .add_row(["IMSI", &self.sim_imsi]) - .add_row(["Download Speed", &self.realtime_rx_thrpt.to_string()]) - .add_row(["Upload Speed", &self.realtime_tx_thrpt.to_string()]) - .add_row(["Realtime RX", &self.realtime_rx_bytes.to_string()]) - .add_row(["Realtime TX", &self.realtime_tx_bytes.to_string()]) - .add_row(["Monthly RX", &self.monthly_rx_bytes.to_string()]) - .add_row(["Monthly TX", &self.monthly_tx_bytes.to_string()]) - .add_row(["Monthly Online", &self.monthly_time.to_string()]); + .add_row(["Status", &internet.ppp_status.to_string()]) + .add_row(["WAN IP", or_dash(&internet.wan_ipaddr)]) + .add_row(["Gateway", or_dash(&self.wan.gateway)]) + .add_row(["Netmask", or_dash(&self.wan.netmask)]) + .add_row(["DNS", &self.wan.dns.to_string()]) + .add_row(["LAN Domain", &internet.lan_domain]) + .add_row(["IMSI", &internet.sim_imsi]) + .add_row(["Download Speed", &internet.realtime_rx_thrpt.to_string()]) + .add_row(["Upload Speed", &internet.realtime_tx_thrpt.to_string()]) + .add_row(["Realtime RX", &internet.realtime_rx_bytes.to_string()]) + .add_row(["Realtime TX", &internet.realtime_tx_bytes.to_string()]) + .add_row(["Monthly RX", &internet.monthly_rx_bytes.to_string()]) + .add_row(["Monthly TX", &internet.monthly_tx_bytes.to_string()]) + .add_row(["Monthly Online", &internet.monthly_time.to_string()]); println!("{table}"); diff --git a/src/proc_get.rs b/src/proc_get.rs index 0222ac9..f78a83e 100644 --- a/src/proc_get.rs +++ b/src/proc_get.rs @@ -334,6 +334,18 @@ impl ProcGet for SimIccid { type Params = (); } +#[derive(Debug, Deserialize)] +pub struct WanDetails { + pub gateway: BoxStr, + pub netmask: BoxStr, + pub dns: DnsServers, +} + +impl ProcGet for WanDetails { + const CMD: &str = "home_get"; + type Params = (); +} + #[derive(Debug)] pub struct DeviceReport { pub device: Device, diff --git a/src/router.rs b/src/router.rs index 06ab882..f773a5f 100644 --- a/src/router.rs +++ b/src/router.rs @@ -264,6 +264,13 @@ impl Router { SignalReport { signal, cell }.show() } + pub async fn show_internet(&self) -> EyreResult<()> { + let internet = self.get_multi::().await?; + let wan = self.get::().await?; + + InternetReport { internet, wan }.show() + } + /// Device identity comes from `home_get`, but the SIM ICCID only /// exists as a standalone cmd; join the two reads into one report. pub async fn show_device(&self) -> EyreResult<()> { diff --git a/src/types.rs b/src/types.rs index d1cf467..5e4fd3e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,6 +3,7 @@ use crate::common::*; use serde::{Deserialize, Deserializer, de::Error as _}; +use std::net::IpAddr; /// `deserialize_with` helpers for fields that don't warrant a dedicated type. pub mod de { @@ -207,6 +208,43 @@ impl std::fmt::Display for Decibels { } } +/// A comma-separated resolver list ("10.44.137.4,10.43.137.4"). +#[derive(Debug, Clone)] +pub struct DnsServers(pub BoxList); + +impl<'de> Deserialize<'de> for DnsServers { + fn deserialize>(deserializer: D) -> Result { + let raw = BoxStr::deserialize(deserializer)?; + raw.split(',') + .map(str::trim) + .filter(|entry| !entry.is_empty()) + .map(|entry| { + entry + .parse() + .map_err(|e| D::Error::custom(format!("invalid DNS address {entry:?}: {e}"))) + }) + .collect::, _>>() + .map(Self) + } +} + +impl std::fmt::Display for DnsServers { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.0.is_empty() { + return write!(f, "—"); + } + + for (index, ip) in self.0.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + write!(f, "{ip}")?; + } + + Ok(()) + } +} + /// WAN connection state (`ppp_status`). #[derive(Debug, Clone)] pub enum PppStatus { -- 2.51.2