Something went wrong. Try again.
htop for your network: a real-time IP traffic monitor for the terminal, ported to Zig from iptop
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132// SPDX-FileCopyrightText: © 2026 Francesc Muñoz// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! What the collectors measure and the panels draw. A sample owns none of its//! memory: everything in one is allocated from the arena of the snapshot it//! belongs to, and goes when that snapshot is replaced.
const std = @import("std");
/// Bytes per second in each direction.pub const Rates = struct { rx: f64 = 0, tx: f64 = 0,
pub fn sum(self: Rates) f64 { return self.rx + self.tx; }};
pub const InterfaceRate = struct { name: []const u8, rx_rate: f64, tx_rate: f64,};
/// The whole machine's traffic, from the interface counters.pub const Throughput = struct { rx_rate: f64 = 0, tx_rate: f64 = 0, rx_total: f64 = 0, tx_total: f64 = 0, interfaces: []const InterfaceRate = &.{},};
/// A socket, as `ss` or `lsof` describe it. `state` uses the BSD names --/// `ESTABLISHED`, `LISTEN`, `SYN_SENT` -- whichever tool it came from, and is/// empty for a UDP socket that has no peer.pub const Connection = struct { command: []const u8, /// Zero when the socket belongs to a process this user cannot see. pid: u32, /// `TCP` or `UDP`. protocol: []const u8, local: []const u8, /// Empty for a socket with no peer. remote: []const u8, /// `remote` with the address replaced by its name, once one is known. remote_display: []const u8, state: []const u8,};
pub const ProcessRate = struct { name: []const u8, pid: u32, rx_rate: f64, tx_rate: f64, rx_total: f64, tx_total: f64,};
pub const RemoteHost = struct { ip: []const u8, /// The name the address resolves to, or the address itself until then. host: []const u8, /// ISO 3166-1 alpha-2, or empty while unknown. country: []const u8, org: []const u8, lat: ?f64, lon: ?f64, rx_rate: f64, tx_rate: f64,};
pub const ProcessConnection = struct { local: []const u8, remote: []const u8, remote_display: []const u8, country: []const u8, rx_rate: f64, tx_rate: f64,};
pub const History = struct { rx: []const f64 = &.{}, tx: []const f64 = &.{},};
/// The per-process and per-host side of the traffic: who is talking, and to/// whom.pub const Traffic = struct { processes: []const ProcessRate = &.{}, remotes: []const RemoteHost = &.{}, /// Keyed by `local|remote`, for joining with the connection list. connection_rates: std.StringHashMapUnmanaged(Rates) = .empty, process_connections: std.AutoHashMapUnmanaged(u32, []const ProcessConnection) = .empty, histories: std.AutoHashMapUnmanaged(u32, History) = .empty,
pub fn rateOf(self: *const Traffic, local: []const u8, remote: []const u8) ?Rates { var key: [256]u8 = undefined; const k = std.fmt.bufPrint(&key, "{s}|{s}", .{ local, remote }) catch return null; return self.connection_rates.get(k); }};
pub const System = struct { host: []const u8 = "", local_ip: []const u8 = "", gateway: []const u8 = "", public_ip: []const u8 = "",};
pub const Latency = struct { gateway_ms: ?f64 = null, internet_ms: ?f64 = null, dns_ms: ?f64 = null, /// The fraction of a burst's probes that got no reply, or null where that /// target was not probed. gateway_loss: ?f64 = null, internet_loss: ?f64 = null, dns_loss: ?f64 = null, dns_server: []const u8 = "",};
/// Where an address is, as ip-api.com answers it.pub const Geo = struct { country: []const u8 = "", org: []const u8 = "", lat: ?f64 = null, lon: ?f64 = null,};