import Foundation import NetworkCityCore // Phase-1 proof of concept. Polls nettop, diffs successive snapshots, and prints // the busiest external flows as live KB/s — i.e. the raw material that will // become cars driving to buildings. setvbuf(stdout, nil, _IONBF, 0) // unbuffered: see output live even when piped let interval: TimeInterval = 2.0 let source = NettopSource() let differ = TrafficDiffer() var warmedUp = false func pad(_ s: String, _ width: Int) -> String { s.count >= width ? String(s.prefix(width)) : s + String(repeating: " ", count: width - s.count) } print("📡 NetworkCity probe — sampling every \(Int(interval))s. Ctrl-C to stop.\n") for await snap in source.snapshots(every: interval) { let deltas = differ.ingest(snap).filter { $0.connection.isExternal } let external = snap.connections.filter(\.isExternal).count if !warmedUp { warmedUp = true print("… warming up (need two samples to compute rates) …\n") continue } let active = deltas.sorted { ($0.inBytesPerSec + $0.outBytesPerSec) > ($1.inBytesPerSec + $1.outBytesPerSec) } let ts = DateFormatter.localizedString(from: snap.timestamp, dateStyle: .none, timeStyle: .medium) print("─── \(ts) \(active.count) active / \(external) external connections ───") print("\(pad("PROCESS", 18)) \(pad("DESTINATION", 24)) ↓ KB/s ↑ KB/s") if active.isEmpty { print(" (quiet — no measurable traffic this interval)") } for d in active.prefix(15) { let dest = d.connection.remote.display print("\(pad(d.connection.processName, 18)) \(pad(dest, 24)) " + "\(String(format: "%9.1f", d.inBytesPerSec / 1024)) \(String(format: "%9.1f", d.outBytesPerSec / 1024))") } print("") }