# NetworkCity A macOS network monitor that renders live traffic as a top-down **city map** — remote hosts become buildings, and your traffic becomes cars driving to them (SimCity-style). This repo currently contains **Phase 1: the proven data layer**. ## Architecture ``` ConnectionSource (protocol) ← the seam: "where bytes come from" │ ├─ NettopSource ← Phase 1: shells out to /usr/bin/nettop (no privileges) └─ (libpcap source) ← Phase 2: real packets (needs privilege / helper tool) │ ▼ ConnectionSnapshot ← list of Connection, with cumulative byte counts │ ▼ SpriteKit "city" (Phase 3) ← buildings + cars; never knows the data source ``` The renderer depends only on `NetworkCityCore`, so the data backend can be swapped without touching the visuals. ## Layout - `Sources/NetworkCityCore/` — models, the `ConnectionSource` protocol, the `nettop` parser (`NettopParser`, pure/testable) and poller (`NettopSource`). - `Sources/nettop-probe/` — Phase-1 CLI proof of concept. Prints live KB/s. - `Tests/` — parser tests pinned to real captured `nettop` output. ## Try it ```sh swift test # parser tests against real fixtures swift run nettop-probe # live traffic, busiest external flows as KB/s ``` ## Key design facts (learned from real output) - **nettop format**: process rows are `Name.PID,bytes_in,bytes_out`; the connection sub-rows beneath inherit that process. IPv4 ports use `:`, IPv6 uses `.` and may carry a `%zone` suffix. - **Rates by diffing**: byte counts are lifetime-cumulative, so we keep the last snapshot and subtract. Robust to nettop quirks; works across fresh invocations. - **Process names are unreliable** — nettop truncates/mangles them (it reported `claude` as `2.1.177`). The **pid is trustworthy**; enrich the real name via `proc_pidpath`/`ps` keyed on pid. (Phase-2 polish.) - **`isExternal`** filters listeners, loopback, and link-local so only real off-box destinations become buildings. ## Roadmap 1. ✅ Data layer + live probe (nettop, no privileges) 2. ✅ SpriteKit city — SwiftUI window, glowing buildings, cars of light (`swift run NetworkCityApp`): cyan cars inbound = downloads, amber outbound = uploads; deterministic building placement; drag to pan, scroll to zoom. 3. ✅ Enrichment — real process names (`proc_pidpath`), reverse-DNS + a curated CIDR table so hosts group into named **districts** (Apple, Google, AWS, Telegram, Local Network…). PTR is primary; the CIDR table catches the no-PTR giants (all of `17.0.0.0/8` is Apple). Run with `NC_DEBUG=1` to log each host→district resolution to stderr. 4. ✅ Hub-and-spoke — busy districts auto-expand into their endpoints (`This Mac → OneDrive → its many servers`); cars route the full two-segment path. Expansion is a pure, tested `ExpansionPolicy` (≥2 endpoints, top-K by bytes, TTL tail to avoid flicker). A single client downloading from a CDN pins to one IP, so fan-out is driven by apps that genuinely spread connections (sync clients, browsers). 5. ✅ Traffic differentiation — cars coloured by protocol class (DNS gold, HTTPS cyan, HTTP orange, QUIC violet, Other slate) since direction is already read from motion. Behaviour reinforces it: DNS = tiny fast sparks, QUIC = streaks, heavy flows = big slow "freight" comets. Classifier is a pure tested `TrafficClass`; HUD shows a legend. 6. ✅ Label anti-overlap (`LayoutSolver`). 7. ✅ Click-to-inspect — click a district hub to open a live panel: total down/up, every endpoint with its reverse-DNS name + per-endpoint rate + protocol-colour dot, and the owning process(es). Click empty space or ✕ to close. A pulsing ring marks the selection. Click vs drag is disambiguated by movement distance. 8. ✅ Latency as distance — distance from downtown = measured round-trip time (unprivileged TCP-connect probe, cached), not geography. GeoIP was rejected because anycast makes it assert a physical fiction; latency is measured so it can't lie. Districts glide to their true distance as probes complete; the inspector shows per-endpoint ms. Pure `LatencyLayout` (log curve) is tested; `LatencyProber` uses Network.framework. Our own pid is filtered out so we don't render our own probes. 9. `MenuBarExtra` shell; optional libpcap source via privileged helper. ### Env flags (opt-in diagnostics) - `NC_DEBUG=1` — log host→district resolution, per-tick top districts, and fan-outs to stderr. - `NC_DEMO=1` — offline demo: feeds a synthetic 8-endpoint "OneDrive" through the real scene so the hub-and-spoke fan-out runs without nettop.