feat: added latency to the Network popup (based on the ICMP requests) (#1707)

feat: removed WiFi network name from the network popup (starting from macOS Sonoma it's not available without CoreLocation access)
This commit is contained in:
Serhiy Mytrovtsiy
2023-12-08 17:58:13 +01:00
parent 4b68b8e8e6
commit 97d884c860
3 changed files with 56 additions and 27 deletions

View File

@@ -96,6 +96,7 @@ public struct Network_Usage: value_t, Codable {
public struct Network_Connectivity: Codable {
var status: Bool = false
var latency: Double = 0
}
public struct Network_Process: Codable {
@@ -239,7 +240,7 @@ public class Network: Module {
private func connectivityCallback(_ raw: Network_Connectivity?) {
guard let value = raw, self.enabled else { return }
self.popupView.connectivityCallback(value.status)
self.popupView.connectivityCallback(value)
self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {

View File

@@ -39,14 +39,13 @@ internal class Popup: PopupWrapper {
private var totalDownloadField: ValueField? = nil
private var statusField: ValueField? = nil
private var connectivityField: ValueField? = nil
private var latencyField: ValueField? = nil
private var publicIPStackView: NSStackView? = nil
private var publicIPv4Field: ValueField? = nil
private var publicIPv6Field: ValueField? = nil
private var ssidField: ValueField? = nil
private var standardField: ValueField? = nil
private var securityField: ValueField? = nil
private var channelField: ValueField? = nil
private var processesView: NSView? = nil
@@ -91,6 +90,8 @@ internal class Popup: PopupWrapper {
return value
}
private var latency: [Double] = []
public init(_ title: String) {
self.title = title
@@ -241,13 +242,12 @@ internal class Popup: PopupWrapper {
self.statusField = popupRow(container, n: 0, title: "\(localizedString("Status")):", value: localizedString("Unknown")).1
self.connectivityField = popupRow(container, n: 0, title: "\(localizedString("Internet connection")):", value: localizedString("Unknown")).1
self.ssidField = popupRow(container, n: 0, title: "\(localizedString("Network")):", value: localizedString("Unknown")).1
self.standardField = popupRow(container, n: 0, title: "\(localizedString("Standard")):", value: localizedString("Unknown")).1
self.securityField = popupRow(container, n: 0, title: "\(localizedString("Security")):", value: localizedString("Unknown")).1
self.channelField = popupRow(container, n: 0, title: "\(localizedString("Channel")):", value: localizedString("Unknown")).1
self.latencyField = popupRow(container, n: 0, title: "\(localizedString("Latency")):", value: "0 ms").1
self.interfaceField = popupRow(container, n: 0, title: "\(localizedString("Interface")):", value: localizedString("Unknown")).1
self.standardField = popupRow(container, n: 0, title: "\(localizedString("Standard")):", value: localizedString("Unknown")).1
self.channelField = popupRow(container, n: 0, title: "\(localizedString("Channel")):", value: localizedString("Unknown")).1
self.macAddressField = popupRow(container, n: 0, title: "\(localizedString("Physical address")):", value: localizedString("Unknown")).1
self.localIPField = popupRow(container, n: 0, title: "\(localizedString("Local IP")):", value: localizedString("Unknown")).1
@@ -371,7 +371,11 @@ internal class Popup: PopupWrapper {
}
if let interface = value.interface {
self.interfaceField?.stringValue = "\(interface.displayName) (\(interface.BSDName))"
var details = interface.BSDName
if value.connectionType == .wifi, let v = value.wifiDetails.RSSI {
details += ", \(v)"
}
self.interfaceField?.stringValue = "\(interface.displayName) (\(details))"
self.macAddressField?.stringValue = interface.address
} else {
self.interfaceField?.stringValue = localizedString("Unknown")
@@ -379,10 +383,6 @@ internal class Popup: PopupWrapper {
}
if value.connectionType == .wifi {
self.ssidField?.stringValue = value.wifiDetails.ssid ?? localizedString("Unknown")
if let v = value.wifiDetails.RSSI {
self.ssidField?.stringValue += " (\(v))"
}
var rssi = localizedString("Unknown")
if let v = value.wifiDetails.RSSI {
rssi = "\(v) dBm"
@@ -395,20 +395,16 @@ internal class Popup: PopupWrapper {
if let v = value.wifiDetails.transmitRate {
txRate = "\(v) Mbps"
}
self.ssidField?.toolTip = "RSSI: \(rssi)\nNoise: \(noise)\nTransmit rate: \(txRate)"
self.standardField?.stringValue = value.wifiDetails.standard ?? localizedString("Unknown")
self.securityField?.stringValue = value.wifiDetails.security ?? localizedString("Unknown")
self.channelField?.stringValue = value.wifiDetails.channel ?? localizedString("Unknown")
let number = value.wifiDetails.channelNumber ?? localizedString("Unknown")
let band = value.wifiDetails.channelBand ?? localizedString("Unknown")
let width = value.wifiDetails.channelWidth ?? localizedString("Unknown")
self.channelField?.toolTip = "Channel number: \(number)\nChannel band: \(band)\nChannel width: \(width)\nTransmit rate: \(txRate)"
self.channelField?.toolTip = "RSSI: \(rssi)\nNoise: \(noise)\nChannel number: \(number)\nChannel band: \(band)\nChannel width: \(width)\nTransmit rate: \(txRate)"
} else {
self.ssidField?.stringValue = localizedString("Unavailable")
self.standardField?.stringValue = localizedString("Unavailable")
self.securityField?.stringValue = localizedString("Unavailable")
self.channelField?.stringValue = localizedString("Unavailable")
}
@@ -445,19 +441,27 @@ internal class Popup: PopupWrapper {
})
}
public func connectivityCallback(_ value: Bool?) {
public func connectivityCallback(_ value: Network_Connectivity?) {
if self.latency.count >= 90 {
self.latency.remove(at: 0)
}
self.latency.append(value?.latency ?? 0)
DispatchQueue.main.async(execute: {
if (self.window?.isVisible ?? false) || !self.connectionInitialized {
var text = "Unknown"
if let v = value {
text = v ? "UP" : "DOWN"
text = v.status ? "UP" : "DOWN"
}
self.connectivityField?.stringValue = localizedString(text)
if !self.latency.isEmpty {
self.latencyField?.stringValue = "\((self.latency.reduce(0, +) / Double(self.latency.count)).rounded(toPlaces: 2)) ms"
}
self.connectionInitialized = true
}
if let value, let chart = self.connectivityChart {
chart.addValue(value)
chart.addValue(value.status)
}
})
}

View File

@@ -304,9 +304,7 @@ internal class UsageReader: Reader<Network_Usage> {
self.getPublicIP()
}
guard self.interfaceID != "" else {
return
}
guard self.interfaceID != "" else { return }
for interface in SCNetworkInterfaceCopyAll() as NSArray {
if let bsdName = SCNetworkInterfaceGetBSDName(interface as! SCNetworkInterface), bsdName as String == self.interfaceID,
@@ -328,6 +326,8 @@ internal class UsageReader: Reader<Network_Usage> {
}
}
guard self.usage.interface != nil else { return }
if let interface = CWWiFiClient.shared().interface(withName: self.interfaceID), self.usage.connectionType == .wifi {
self.usage.wifiDetails.ssid = interface.ssid()
self.usage.wifiDetails.bssid = interface.bssid()
@@ -612,6 +612,18 @@ internal class ConnectivityReader: Reader<Network_Connectivity> {
}
}
private var _latency: Double? = nil
private var latency: Double? {
get {
self.variablesQueue.sync { self._latency }
}
set {
self.variablesQueue.sync { self._latency = newValue }
}
}
var start: DispatchTime? = nil
private struct ICMPHeader {
public var type: UInt8
public var code: UInt8
@@ -667,6 +679,7 @@ internal class ConnectivityReader: Reader<Network_Connectivity> {
let timer = Timer(timeInterval: self.timeout, target: self, selector: #selector(self.timeoutCallback), userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: .common)
self.timeoutTimer = timer
self.start = DispatchTime.now()
let error = CFSocketSendData(socket, addr as CFData, data as CFData, self.timeout)
if error != .success {
@@ -675,6 +688,9 @@ internal class ConnectivityReader: Reader<Network_Connectivity> {
if let v = self.status {
self.wrapper.status = v
if let l = self.latency {
self.wrapper.latency = l
}
self.callback(self.wrapper)
}
}
@@ -686,7 +702,9 @@ internal class ConnectivityReader: Reader<Network_Connectivity> {
private func socketCallback(data: Data? = nil, error: CFSocketError? = nil) {
guard let data = data, validateResponse(data) else { return }
let end = DispatchTime.now()
self.latency = Double(end.uptimeNanoseconds - (self.start?.uptimeNanoseconds ?? 0)) / 1_000_000
self.status = error == nil
self.isPinging = false
self.timeoutTimer?.invalidate()
@@ -713,7 +731,14 @@ internal class ConnectivityReader: Reader<Network_Connectivity> {
}
private func request() -> Data? {
var header = ICMPHeader(type: 8, code: 0, checksum: 0, identifier: CFSwapInt16HostToBig(self.identifier), sequenceNumber: CFSwapInt16HostToBig(0), payload: self.fingerprint.uuid)
var header = ICMPHeader(
type: 8,
code: 0,
checksum: 0,
identifier: CFSwapInt16HostToBig(self.identifier),
sequenceNumber: CFSwapInt16HostToBig(0),
payload: self.fingerprint.uuid
)
let delta = MemoryLayout<uuid_t>.size - MemoryLayout<uuid_t>.size
var additional = [UInt8]()
@@ -724,8 +749,7 @@ internal class ConnectivityReader: Reader<Network_Connectivity> {
guard let checksum = computeChecksum(header: header, additionalPayload: additional) else { return nil }
header.checksum = checksum
let package = Data(bytes: &header, count: MemoryLayout<ICMPHeader>.size) + Data(additional)
return package
return Data(bytes: &header, count: MemoryLayout<ICMPHeader>.size) + Data(additional)
}
private func computeChecksum(header: ICMPHeader, additionalPayload: [UInt8]) -> UInt16? {