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 } }