Files

49 lines
1.9 KiB
Swift
Raw Permalink Normal View History

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