diff --git a/Modules/Net/main.swift b/Modules/Net/main.swift index 0fb27606..b7a9a183 100644 --- a/Modules/Net/main.swift +++ b/Modules/Net/main.swift @@ -31,6 +31,37 @@ public struct Network_addr { var v6: String? = nil } +public struct Network_wifi { + var countryCode: String? = nil + var ssid: String? = nil + var RSSI: Int? = nil + var noise: Int? = nil + var transmitRate: Double? = nil + var transmitPower: Int? = nil + + var standard: String? = nil + var mode: String? = nil + var security: String? = nil + var channel: String? = nil + + var channelBand: String? = nil + var channelWidth: String? = nil + var channelNumber: String? = nil + + mutating func reset() { + self.countryCode = nil + self.ssid = nil + self.RSSI = nil + self.noise = nil + self.transmitRate = nil + self.transmitPower = nil + self.standard = nil + self.mode = nil + self.security = nil + self.channel = nil + } +} + public struct Network_Usage: value_t { var bandwidth: Bandwidth = (0, 0) var total: Bandwidth = (0, 0) @@ -42,8 +73,7 @@ public struct Network_Usage: value_t { var connectionType: Network_t? = nil var status: Bool = false - var countryCode: String? = nil - var ssid: String? = nil + var wifiDetails: Network_wifi = Network_wifi() mutating func reset() { self.bandwidth = (0, 0) @@ -54,8 +84,7 @@ public struct Network_Usage: value_t { self.interface = nil self.connectionType = nil - self.countryCode = nil - self.ssid = nil + self.wifiDetails.reset() } public var widgetValue: Double = 0 diff --git a/Modules/Net/popup.swift b/Modules/Net/popup.swift index c5901abb..a510c561 100644 --- a/Modules/Net/popup.swift +++ b/Modules/Net/popup.swift @@ -32,7 +32,6 @@ internal class Popup: NSStackView, Popup_p { private var localIPField: ValueField? = nil private var interfaceField: ValueField? = nil - private var ssidField: ValueField? = nil private var macAdressField: ValueField? = nil private var totalUploadField: ValueField? = nil private var totalDownloadField: ValueField? = nil @@ -42,6 +41,11 @@ internal class Popup: NSStackView, Popup_p { 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 private var initialized: Bool = false @@ -182,10 +186,15 @@ internal class Popup: NSStackView, Popup_p { self.totalUploadField = popupWithColorRow(container, color: NSColor.systemRed, n: 5, title: "\(localizedString("Total upload")):", value: "0") self.totalDownloadField = popupWithColorRow(container, color: NSColor.systemBlue, n: 4, title: "\(localizedString("Total download")):", value: "0") - self.connectionField = popupRow(container, n: 4, title: "\(localizedString("Status")):", value: localizedString("Unknown")).1 - self.interfaceField = popupRow(container, n: 3, title: "\(localizedString("Interface")):", value: localizedString("Unknown")).1 - self.ssidField = popupRow(container, n: 2, title: "\(localizedString("Network")):", value: localizedString("Unknown")).1 - self.macAdressField = popupRow(container, n: 1, title: "\(localizedString("Physical address")):", value: localizedString("Unknown")).1 + self.connectionField = popupRow(container, n: 0, title: "\(localizedString("Status")):", 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.interfaceField = popupRow(container, n: 0, title: "\(localizedString("Interface")):", value: localizedString("Unknown")).1 + self.macAdressField = 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 self.localIPField?.isSelectable = true @@ -308,14 +317,28 @@ internal class Popup: NSStackView, Popup_p { } if value.connectionType == .wifi { - self.ssidField?.stringValue = value.ssid ?? "Unknown" + self.ssidField?.stringValue = value.wifiDetails.ssid ?? localizedString("Unknown") + if let v = value.wifiDetails.RSSI { + self.ssidField?.stringValue += " (\(v))" + } + 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)" } else { self.ssidField?.stringValue = localizedString("Unavailable") + self.standardField?.stringValue = localizedString("Unavailable") + self.securityField?.stringValue = localizedString("Unavailable") + self.channelField?.stringValue = localizedString("Unavailable") } if let view = self.publicIPv4Field, view.stringValue != value.raddr.v4 { if let addr = value.raddr.v4 { - view.stringValue = (value.countryCode != nil) ? "\(addr) (\(value.countryCode!))" : addr + view.stringValue = (value.wifiDetails.countryCode != nil) ? "\(addr) (\(value.wifiDetails.countryCode!))" : addr } else { view.stringValue = localizedString("Unknown") } diff --git a/Modules/Net/readers.swift b/Modules/Net/readers.swift index dc0280e5..4741b24b 100644 --- a/Modules/Net/readers.swift +++ b/Modules/Net/readers.swift @@ -8,6 +8,7 @@ // // Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. // +// swiftlint:disable control_statement import Cocoa import Kit @@ -20,6 +21,85 @@ struct ipResponse: Decodable { var cc: String } +extension CWPHYMode: CustomStringConvertible { + public var description: String { + switch(self) { + case .mode11a: return "802.11a" + case .mode11ac: return "802.11ac" + case .mode11b: return "802.11b" + case .mode11g: return "802.11g" + case .mode11n: return "802.11n" + case .modeNone: return "none" + @unknown default: return "unknown" + } + } +} + +extension CWInterfaceMode: CustomStringConvertible { + public var description: String { + switch(self) { + case .hostAP: return "AP" + case .IBSS: return "Adhoc" + case .station: return "Station" + case .none: return "none" + @unknown default: return "unknown" + } + } +} + +extension CWSecurity: CustomStringConvertible { + public var description: String { + switch(self) { + case .none: return "none" + case .WEP: return "WEP" + case .wpaPersonal: return "WPA Personal" + case .wpaPersonalMixed: return "WPA Personal Mixed" + case .wpa2Personal: return "WPA2 Personal" + case .personal: return "Personal" + case .dynamicWEP: return "Dynamic WEP" + case .wpaEnterprise: return "WPA Enterprise" + case .wpaEnterpriseMixed: return "WPA Enterprise Mixed" + case .wpa2Enterprise: return "WPA2 Enterprise" + case .enterprise: return "Enterprise" + case .unknown: return "unknown" + case .wpa3Personal: return "WPA3 Personal" + case .wpa3Enterprise: return "WPA3 Enterprise" + case .wpa3Transition: return "WPA3 Transition" + @unknown default: return "unknown" + } + } +} + +extension CWChannelBand: CustomStringConvertible { + public var description: String { + switch(self) { + case .band2GHz: return "2 GHz" + case .band5GHz: return "5 Ghz" + case .bandUnknown: return "unknown" + @unknown default: return "unknown" + } + } +} + +extension CWChannelWidth: CustomStringConvertible { + public var description: String { + switch(self) { + case .width20MHz: return "20 MHz" + case .width40MHz: return "40 MHz" + case .width80MHz: return "80 MHz" + case .width160MHz: return "160 MHz" + case .widthUnknown: return "unknown" + @unknown default: return "unknown" + } + } +} + +extension CWChannel { + override public var description: String { + return "\(channelNumber) (\(channelBand), \(channelWidth))" + } +} + internal class UsageReader: Reader { private var reachability: Reachability = Reachability(start: true) private var usage: Network_Usage = Network_Usage() @@ -212,32 +292,50 @@ internal class UsageReader: Reader { self.getPublicIP() } - if self.interfaceID != "" { - for interface in SCNetworkInterfaceCopyAll() as NSArray { - if let bsdName = SCNetworkInterfaceGetBSDName(interface as! SCNetworkInterface), - bsdName as String == self.interfaceID, - let type = SCNetworkInterfaceGetInterfaceType(interface as! SCNetworkInterface), - let displayName = SCNetworkInterfaceGetLocalizedDisplayName(interface as! SCNetworkInterface), - let address = SCNetworkInterfaceGetHardwareAddressString(interface as! SCNetworkInterface) { - self.usage.interface = Network_interface(displayName: displayName as String, BSDName: bsdName as String, address: address as String) - - switch type { - case kSCNetworkInterfaceTypeEthernet: - self.usage.connectionType = .ethernet - case kSCNetworkInterfaceTypeIEEE80211, kSCNetworkInterfaceTypeWWAN: - self.usage.connectionType = .wifi - case kSCNetworkInterfaceTypeBluetooth: - self.usage.connectionType = .bluetooth - default: - self.usage.connectionType = .other - } + guard self.interfaceID != "" else { + return + } + + for interface in SCNetworkInterfaceCopyAll() as NSArray { + if let bsdName = SCNetworkInterfaceGetBSDName(interface as! SCNetworkInterface), bsdName as String == self.interfaceID, + let type = SCNetworkInterfaceGetInterfaceType(interface as! SCNetworkInterface), + let displayName = SCNetworkInterfaceGetLocalizedDisplayName(interface as! SCNetworkInterface), + let address = SCNetworkInterfaceGetHardwareAddressString(interface as! SCNetworkInterface) { + self.usage.interface = Network_interface(displayName: displayName as String, BSDName: bsdName as String, address: address as String) + + switch type { + case kSCNetworkInterfaceTypeEthernet: + self.usage.connectionType = .ethernet + case kSCNetworkInterfaceTypeIEEE80211, kSCNetworkInterfaceTypeWWAN: + self.usage.connectionType = .wifi + case kSCNetworkInterfaceTypeBluetooth: + self.usage.connectionType = .bluetooth + default: + self.usage.connectionType = .other } } } - if let interface = CWWiFiClient.shared().interface(), self.usage.connectionType == .wifi { - self.usage.ssid = interface.ssid() - self.usage.countryCode = interface.countryCode() + if let interface = CWWiFiClient.shared().interface(withName: self.interfaceID), self.usage.connectionType == .wifi { + self.usage.wifiDetails.ssid = interface.ssid() + self.usage.wifiDetails.countryCode = interface.countryCode() + + self.usage.wifiDetails.RSSI = interface.rssiValue() + self.usage.wifiDetails.noise = interface.noiseMeasurement() + self.usage.wifiDetails.transmitRate = interface.transmitRate() + self.usage.wifiDetails.transmitPower = interface.transmitPower() + + self.usage.wifiDetails.standard = interface.activePHYMode().description + self.usage.wifiDetails.mode = interface.interfaceMode().description + self.usage.wifiDetails.security = interface.security().description + + if let ch = interface.wlanChannel() { + self.usage.wifiDetails.channel = ch.description + + self.usage.wifiDetails.channelBand = ch.channelBand.description + self.usage.wifiDetails.channelWidth = ch.channelWidth.description + self.usage.wifiDetails.channelNumber = ch.channelNumber.description + } } }