import Foundation /// Rates are computed per container so new or removed containers do not cause /// spikes from their lifetime counters. Counter resets contribute zero. public struct NetworkRateTracker: Sendable { private struct Counter: Sendable { var date: Date; var rx: Double; var tx: Double } private var counters: [String: Counter] = [:] public init() {} public mutating func sample(_ resources: [Resource], at date: Date) -> (rx: Double, tx: Double) { var next: [String: Counter] = [:], rxRate = 0.0, txRate = 0.0 for resource in resources { guard let rx = resource.rxBytes, let tx = resource.txBytes else { continue } if let previous = counters[resource.id] { let seconds = date.timeIntervalSince(previous.date) if seconds > 0 { rxRate += max(0, rx - previous.rx) / seconds; txRate += max(0, tx - previous.tx) / seconds } } next[resource.id] = Counter(date: date, rx: rx, tx: tx) } counters = next return (rxRate, txRate) } }