nettop 0.1.1

CLI network usage monitor by application — like NetLimiter for the terminal
/// Linux-specific network I/O tracking
///
/// Strategy:
///   1. If process has its own net namespace → /proc/<pid>/net/dev (accurate)
///   2. If shared namespace (containers, host) → return None → collector falls
///      back to sysinfo disk I/O as an activity proxy
///
/// On macOS/Windows: always returns None, collector uses sysinfo.

#[cfg(target_os = "linux")]
mod linux {
    use std::fs;

    pub fn read_net_dev(pid: u32) -> Option<(u64, u64)> {
        let path = format!("/proc/{}/net/dev", pid);
        let content = fs::read_to_string(&path).ok()?;
        let mut recv: u64 = 0;
        let mut sent: u64 = 0;
        let mut found = false;
        for line in content.lines().skip(2) {
            let line = line.trim();
            if line.starts_with("lo:") {
                continue;
            }
            let data = line.splitn(2, ':').nth(1)?.trim();
            let f: Vec<&str> = data.split_whitespace().collect();
            if f.len() < 9 {
                continue;
            }
            recv = recv.saturating_add(f[0].parse::<u64>().unwrap_or(0));
            sent = sent.saturating_add(f[8].parse::<u64>().unwrap_or(0));
            found = true;
        }
        if found {
            Some((sent, recv))
        } else {
            None
        }
    }

    /// Returns true if pid shares the root net namespace (no isolation)
    pub fn shares_root_netns(pid: u32) -> bool {
        let init = std::fs::read_link("/proc/1/ns/net").ok();
        let mine = std::fs::read_link(format!("/proc/{}/ns/net", pid)).ok();
        match (init, mine) {
            (Some(a), Some(b)) => a == b,
            _ => false,
        }
    }
}

#[cfg(target_os = "linux")]
pub fn read_proc_net_bytes(pid: u32) -> Option<(u64, u64)> {
    // Only use per-pid net/dev when the process has its own namespace
    if linux::shares_root_netns(pid) {
        return None;
    }
    linux::read_net_dev(pid)
}

#[cfg(not(target_os = "linux"))]
pub fn read_proc_net_bytes(_pid: u32) -> Option<(u64, u64)> {
    None
}