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,69 @@
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
/// Measures round-trip time to an endpoint with an unprivileged TCP connect
|
||||
/// (time from start to `.ready` ≈ one handshake RTT). Results are cached.
|
||||
///
|
||||
/// We probe a port we've already seen traffic on, so we're not knocking on
|
||||
/// closed doors — and the connection carries no data, just the handshake.
|
||||
public actor LatencyProber {
|
||||
private var cache: [String: Double] = [:]
|
||||
|
||||
public init() {}
|
||||
|
||||
public func cached(_ host: String) -> Double? { cache[host] }
|
||||
|
||||
/// Measure (or refresh) RTT in milliseconds. Returns nil if unreachable.
|
||||
public func measure(host: String, port: UInt16) async -> Double? {
|
||||
let rtt = await Self.tcpHandshakeRTT(host: host, port: port)
|
||||
if let rtt { cache[host] = rtt }
|
||||
return rtt
|
||||
}
|
||||
|
||||
private static func tcpHandshakeRTT(host: String, port: UInt16) async -> Double? {
|
||||
guard let nwPort = NWEndpoint.Port(rawValue: port) else { return nil }
|
||||
|
||||
return await withCheckedContinuation { (cont: CheckedContinuation<Double?, Never>) in
|
||||
let conn = NWConnection(host: NWEndpoint.Host(host), port: nwPort, using: .tcp)
|
||||
let queue = DispatchQueue(label: "latency.probe")
|
||||
let start = DispatchTime.now()
|
||||
let state = ProbeState(conn: conn, cont: cont)
|
||||
|
||||
conn.stateUpdateHandler = { st in
|
||||
switch st {
|
||||
case .ready:
|
||||
let ns = DispatchTime.now().uptimeNanoseconds - start.uptimeNanoseconds
|
||||
state.finish(Double(ns) / 1_000_000)
|
||||
case .failed, .cancelled:
|
||||
state.finish(nil)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
conn.start(queue: queue)
|
||||
queue.asyncAfter(deadline: .now() + 2) { state.finish(nil) } // timeout
|
||||
}
|
||||
}
|
||||
|
||||
/// Resumes the continuation exactly once, whichever callback fires first.
|
||||
private final class ProbeState: @unchecked Sendable {
|
||||
private let lock = NSLock()
|
||||
private var done = false
|
||||
private let conn: NWConnection
|
||||
private let cont: CheckedContinuation<Double?, Never>
|
||||
|
||||
init(conn: NWConnection, cont: CheckedContinuation<Double?, Never>) {
|
||||
self.conn = conn
|
||||
self.cont = cont
|
||||
}
|
||||
|
||||
func finish(_ value: Double?) {
|
||||
lock.lock()
|
||||
if done { lock.unlock(); return }
|
||||
done = true
|
||||
lock.unlock()
|
||||
conn.cancel()
|
||||
cont.resume(returning: value)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user