49 lines
1.9 KiB
Swift
49 lines
1.9 KiB
Swift
|
|
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
|
||
|
|
}
|
||
|
|
}
|