Fix: No download speed (#157)

* Implemented alternative approach to get download speed

* Early check

* Reset data on interface change

* Trigger alternative approach manually

* Fix
This commit is contained in:
Ahmed Osama
2020-11-26 17:02:04 +02:00
committed by GitHub
parent 2876fddc4f
commit 6b58302089

View File

@@ -24,11 +24,15 @@ struct ipResponse: Decodable {
}
internal class UsageReader: Reader<Network_Usage> {
typealias BandwidthUsage = (upload: Int64, download: Int64)
public var store: UnsafePointer<Store>? = nil
private var reachability: Reachability? = nil
private var usage: Network_Usage = Network_Usage()
private var shouldReportSelectedInterfaceBandwidthOnly = true
private var primaryInterface: String {
get {
if let global = SCDynamicStoreCopyValue(nil, "State:/Network/Global/IPv4" as CFString), let name = global["PrimaryInterface"] as? String {
@@ -69,51 +73,23 @@ internal class UsageReader: Reader<Network_Usage> {
}
public override func read() {
var interfaceAddresses: UnsafeMutablePointer<ifaddrs>? = nil
var upload: Int64 = 0
var download: Int64 = 0
guard getifaddrs(&interfaceAddresses) == 0 else { return }
var pointer = interfaceAddresses
while pointer != nil {
defer { pointer = pointer?.pointee.ifa_next }
if String(cString: pointer!.pointee.ifa_name) != self.interfaceID {
continue
}
if let ip = getLocalIP(pointer!), self.usage.laddr != ip {
self.usage.laddr = ip
}
if let info = getBytesInfo(pointer!) {
upload += info.upload
download += info.download
}
}
freeifaddrs(interfaceAddresses)
if self.usage.upload != 0 {
self.usage.upload = upload - self.usage.upload
}
if self.usage.download != 0 {
self.usage.download = download - self.usage.download
let currentUsage: BandwidthUsage
if shouldReportSelectedInterfaceBandwidthOnly {
currentUsage = interfaceBandwidthUsage()
} else {
currentUsage = allProcessesBandwidthUsage()
}
if self.usage.upload < 0 {
self.usage.upload = 0
}
if self.usage.download < 0 {
self.usage.download = 0
}
self.usage.upload = max(currentUsage.upload - self.usage.upload, 0)
self.usage.download = max(currentUsage.download - self.usage.download, 0)
self.usage.totalUpload += self.usage.upload
self.usage.totalDownload += self.usage.download
self.callback(self.usage)
self.usage.upload = upload
self.usage.download = download
self.usage.upload = currentUsage.upload
self.usage.download = currentUsage.download
}
public func getDetails() {
@@ -196,6 +172,89 @@ internal class UsageReader: Reader<Network_Usage> {
let data: UnsafeMutablePointer<if_data>? = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
return (upload: Int64(data?.pointee.ifi_obytes ?? 0), download: Int64(data?.pointee.ifi_ibytes ?? 0))
}
private func interfaceBandwidthUsage() -> BandwidthUsage {
var interfaceAddresses: UnsafeMutablePointer<ifaddrs>? = nil
var totalUpload: Int64 = 0
var totalDownload: Int64 = 0
guard getifaddrs(&interfaceAddresses) == 0 else {
return (0, 0)
}
var pointer = interfaceAddresses
while pointer != nil {
defer { pointer = pointer?.pointee.ifa_next }
if String(cString: pointer!.pointee.ifa_name) != self.interfaceID {
continue
}
if let ip = getLocalIP(pointer!), self.usage.laddr != ip {
self.usage.laddr = ip
}
if let info = getBytesInfo(pointer!) {
totalUpload += info.upload
totalDownload += info.download
}
}
freeifaddrs(interfaceAddresses)
return (totalUpload, totalDownload)
}
private func allProcessesBandwidthUsage() -> BandwidthUsage {
let task = Process()
task.launchPath = "/usr/bin/nettop"
task.arguments = ["-P", "-L", "1", "-k", "time,interface,state,rx_dupe,rx_ooo,re-tx,rtt_avg,rcvsize,tx_win,tc_class,tc_mgt,cc_algo,P,C,R,W,arch"]
let outputPipe = Pipe()
let errorPipe = Pipe()
task.standardOutput = outputPipe
task.standardError = errorPipe
do {
try task.run()
} catch let error {
print(error)
return (0, 0)
}
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
let output = String(decoding: outputData, as: UTF8.self)
_ = String(decoding: errorData, as: UTF8.self)
if output.isEmpty {
return (0, 0)
}
var totalUpload: Int64 = 0
var totalDownload: Int64 = 0
var firstLine = false
output.enumerateLines { (line, _) -> () in
if !firstLine {
firstLine = true
return
}
let parsedLine = line.split(separator: ",")
guard parsedLine.count >= 3 else {
return
}
if let download = Int(parsedLine[1]) {
totalDownload += Int64(download)
}
if let upload = Int(parsedLine[2]) {
totalUpload += Int64(upload)
}
}
return (totalUpload, totalDownload)
}
}
public class ProcessReader: Reader<[Network_Process]> {