Initial commit: NetworkCity — network traffic as a neon city
A native macOS network monitor that renders live traffic as a top-down neon city: your Mac is downtown, remote orgs are glowing districts, and traffic is cars of light driving the roads. Architecture: - NetworkCityCore: swappable data layer behind a ConnectionSource protocol (nettop-backed today), plus pure/tested logic — traffic diffing, org classification (reverse-DNS + CIDR), traffic classes, hub-and-spoke expansion policy, label anti-overlap, and latency→distance layout. - NetworkCityApp: SwiftUI + SpriteKit city — auto-expanding districts, protocol-coloured cars, click-to-inspect panel, and latency-as-distance (districts glide to their measured RTT). - nettop-probe: CLI proof of the data layer. 44 tests passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import Foundation
|
||||
|
||||
/// One connection's traffic over the interval between two snapshots.
|
||||
public struct TrafficDelta: Sendable {
|
||||
public let connection: Connection
|
||||
public let bytesInDelta: UInt64
|
||||
public let bytesOutDelta: UInt64
|
||||
public let interval: TimeInterval
|
||||
|
||||
public var inBytesPerSec: Double { interval > 0 ? Double(bytesInDelta) / interval : 0 }
|
||||
public var outBytesPerSec: Double { interval > 0 ? Double(bytesOutDelta) / interval : 0 }
|
||||
}
|
||||
|
||||
/// Turns the stream of cumulative-byte snapshots into per-interval deltas by
|
||||
/// remembering the previous reading for each connection key. Shared by the CLI
|
||||
/// probe and the SpriteKit city so there's one source of truth for "traffic".
|
||||
///
|
||||
/// Not thread-safe by design — drive it from a single actor/thread.
|
||||
public final class TrafficDiffer {
|
||||
private var previous: [String: (UInt64, UInt64)] = [:]
|
||||
private var lastTimestamp: Date?
|
||||
|
||||
public init() {}
|
||||
|
||||
public func ingest(_ snapshot: ConnectionSnapshot) -> [TrafficDelta] {
|
||||
let interval = lastTimestamp.map { snapshot.timestamp.timeIntervalSince($0) } ?? 0
|
||||
lastTimestamp = snapshot.timestamp
|
||||
|
||||
var next: [String: (UInt64, UInt64)] = [:]
|
||||
var deltas: [TrafficDelta] = []
|
||||
|
||||
for c in snapshot.connections {
|
||||
next[c.key] = (c.bytesIn, c.bytesOut)
|
||||
guard interval > 0, let (pIn, pOut) = previous[c.key] else { continue }
|
||||
// A drop in the counter means the tuple was reused by a new connection;
|
||||
// treat as zero rather than underflow.
|
||||
let dIn = c.bytesIn >= pIn ? c.bytesIn - pIn : 0
|
||||
let dOut = c.bytesOut >= pOut ? c.bytesOut - pOut : 0
|
||||
if dIn + dOut > 0 {
|
||||
deltas.append(TrafficDelta(
|
||||
connection: c, bytesInDelta: dIn, bytesOutDelta: dOut, interval: interval
|
||||
))
|
||||
}
|
||||
}
|
||||
previous = next
|
||||
return deltas
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user