diff --git a/Stats/AppDelegate.swift b/Stats/AppDelegate.swift index 014f3af8..7c411d06 100755 --- a/Stats/AppDelegate.swift +++ b/Stats/AppDelegate.swift @@ -1,6 +1,6 @@ // // AppDelegate.swift -// Mini Stats +// Stats // // Created by Serhiy Mytrovtsiy on 28.05.2019. // Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. @@ -10,7 +10,7 @@ import Cocoa import ServiceManagement import LaunchAtLogin -let modules: Observable<[Module]> = Observable([CPU(), Memory(), Disk(), Battery(), Network()]) +let modules: [Module] = [CPU(), Memory(), Disk(), Battery(), Network()] let updater = macAppUpdater(user: "exelban", repo: "stats") let popover = NSPopover() var menuBar: MenuBar? @@ -67,8 +67,8 @@ class AppDelegate: NSObject, NSApplicationDelegate { } func applicationWillTerminate(_ aNotification: Notification) { - if modules.value.count != 0 { - for module in modules.value{ + if modules.count != 0 { + for module in modules { module.stop() } } diff --git a/Stats/MenuBar.swift b/Stats/MenuBar.swift index aace59f2..a94f2907 100644 --- a/Stats/MenuBar.swift +++ b/Stats/MenuBar.swift @@ -18,7 +18,7 @@ class MenuBar { self.menuBarItem = menuBarItem self.menuBarButton = menuBarButton - for module in modules.value { + for module in modules { module.active.subscribe(observer: self) { (value, _) in if !value { let emptyWidget = Empty() @@ -37,7 +37,7 @@ class MenuBar { } public func updateWidget(name: String) { - let newViewList = modules.value.filter{ $0.name == name } + let newViewList = modules.filter{ $0.name == name } if newViewList.isEmpty { return } @@ -56,7 +56,7 @@ class MenuBar { private func updateWidth() { var WIDTH: CGFloat = 0 - for module in modules.value { + for module in modules { if module.active.value && module.available.value { WIDTH = WIDTH + module.view.frame.size.width } @@ -82,7 +82,7 @@ class MenuBar { self.stackView = stackView var WIDTH: CGFloat = 0 - for module in modules.value { + for module in modules { if module.available.value { if module.active.value { module.initWidget() diff --git a/Stats/Modules/Battery/BatteryReader.swift b/Stats/Modules/Battery/BatteryReader.swift index 4006b2cd..eaf7bcf3 100644 --- a/Stats/Modules/Battery/BatteryReader.swift +++ b/Stats/Modules/Battery/BatteryReader.swift @@ -58,6 +58,10 @@ class BatteryReader: Reader { if self.available { self.read() } + + self.timer = Repeater.init(interval: .seconds(1), observer: { _ in + self.read() + }) } func start() { @@ -184,6 +188,6 @@ class BatteryReader: Reader { } self.updateInterval = value - self.timer?.reset(.seconds(Double(value))) + self.timer?.reset(.seconds(Double(value)), restart: false) } } diff --git a/Stats/Modules/CPU/CPUReader.swift b/Stats/Modules/CPU/CPUReader.swift index d0c1e34f..64857582 100644 --- a/Stats/Modules/CPU/CPUReader.swift +++ b/Stats/Modules/CPU/CPUReader.swift @@ -59,12 +59,12 @@ class CPUReader: Reader { self.read() } - self.timer = Repeater.every(.seconds(1)) { timer in + self.timer = Repeater.init(interval: .seconds(1), observer: { _ in self.read() - } - self.additionalTimer = Repeater.every(.seconds(1)) { timer in + }) + self.additionalTimer = Repeater.init(interval: .seconds(1), observer: { _ in self.readAdditional() - } + }) } func start() { @@ -142,7 +142,7 @@ class CPUReader: Reader { var numCPUsU: natural_t = 0 let err: kern_return_t = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo); let usage = getUsage() -// + if err == KERN_SUCCESS { CPUUsageLock.lock() @@ -251,8 +251,8 @@ class CPUReader: Reader { } self.updateInterval = value - self.timer?.reset(.seconds(Double(value))) - self.additionalTimer?.reset(.seconds(Double(value))) + self.timer?.reset(.seconds(Double(value)), restart: false) + self.additionalTimer?.reset(.seconds(Double(value)), restart: false) } } diff --git a/Stats/Modules/Disk/DiskReader.swift b/Stats/Modules/Disk/DiskReader.swift index 768ed298..00bff70a 100644 --- a/Stats/Modules/Disk/DiskReader.swift +++ b/Stats/Modules/Disk/DiskReader.swift @@ -21,6 +21,10 @@ class DiskReader: Reader { if self.available { self.read() } + + self.timer = Repeater.init(interval: .seconds(1), observer: { _ in + self.read() + }) } func start() { @@ -70,6 +74,6 @@ class DiskReader: Reader { } self.updateInterval = value - self.timer?.reset(.seconds(Double(value))) + self.timer?.reset(.seconds(Double(value)), restart: false) } } diff --git a/Stats/Modules/Memory/MemoryReader.swift b/Stats/Modules/Memory/MemoryReader.swift index 4481c865..f1fbca0a 100644 --- a/Stats/Modules/Memory/MemoryReader.swift +++ b/Stats/Modules/Memory/MemoryReader.swift @@ -49,12 +49,12 @@ class MemoryReader: Reader { self.read() } - self.timer = Repeater.every(.seconds(1)) { timer in + self.timer = Repeater.init(interval: .seconds(1), observer: { _ in self.read() - } - self.additionalTimer = Repeater.every(.seconds(1)) { timer in + }) + self.additionalTimer = Repeater.init(interval: .seconds(1), observer: { _ in self.readAdditional() - } + }) } func start() { @@ -165,7 +165,7 @@ class MemoryReader: Reader { } self.updateInterval = value - self.timer?.reset(.seconds(Double(value))) - self.additionalTimer?.reset(.seconds(Double(value))) + self.timer?.reset(.seconds(Double(value)), restart: false) + self.additionalTimer?.reset(.seconds(Double(value)), restart: false) } } diff --git a/Stats/Modules/Network/NetworkReader.swift b/Stats/Modules/Network/NetworkReader.swift index c9a255ed..7d1b9812 100644 --- a/Stats/Modules/Network/NetworkReader.swift +++ b/Stats/Modules/Network/NetworkReader.swift @@ -14,59 +14,80 @@ class NetworkReader: Reader { public var availableAdditional: Bool = false public var updateInterval: Int = 0 - private var netProcess: Process = Process() - private var pipe: Pipe = Pipe() + private var timer: Repeater? + private var uploadValue: Int64 = 0 + private var downloadValue: Int64 = 0 + init() { self.value = Observable([]) - netProcess.launchPath = "/usr/bin/env" - netProcess.arguments = ["netstat", "-w1", "-l", "en0"] - netProcess.standardOutput = pipe if self.available { self.read() } + + self.timer = Repeater.init(interval: .seconds(1), observer: { _ in + self.read() + }) } func start() { - if netProcess.isRunning { - return - } - self.pipe.fileHandleForReading.waitForDataInBackgroundAndNotify() - - NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: self.pipe.fileHandleForReading , queue: nil) { _ -> Void in - defer { - self.pipe.fileHandleForReading.waitForDataInBackgroundAndNotify() - } - - let output = self.pipe.fileHandleForReading.availableData - if output.isEmpty { - return - } - - let outputString = String(data: output, encoding: String.Encoding.utf8) ?? "" - let arr = outputString.condenseWhitespace().split(separator: " ") - - if !arr.isEmpty && Int64(arr[0]) != nil { - guard let download = Int64(arr[2]), let upload = Int64(arr[5]) else { - return - } - self.value << [Double(download), Double(upload)] - } - } - - do { - try netProcess.run() - } catch let error { - print(error) + read() + if self.timer != nil && self.timer!.state.isRunning == false { + self.timer!.start() } } func stop() { - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSFileHandleDataAvailable, object: nil) + self.timer?.pause() } - func read() {} + func read() { + var interfaceAddresses: UnsafeMutablePointer? = nil + + var upload: Int64 = 0 + var download: Int64 = 0 + guard getifaddrs(&interfaceAddresses) == 0 else { return } + + var pointer = interfaceAddresses + while pointer != nil { + guard let info = getDataUsageInfo(from: pointer!) else { + pointer = pointer!.pointee.ifa_next + continue + } + pointer = pointer!.pointee.ifa_next + upload = info[0] + download = info[1] + } + freeifaddrs(interfaceAddresses) + + let lastUpload = self.uploadValue + let lastDownload = self.downloadValue + if lastUpload != 0 && lastDownload != 0 { + DispatchQueue.main.async(execute: { + self.value << [Double(download - lastDownload), Double(upload - lastUpload)] + }) + } + + self.uploadValue = upload + self.downloadValue = download + } + + func getDataUsageInfo(from infoPointer: UnsafeMutablePointer) -> [Int64]? { + let pointer = infoPointer + + let name: String! = String(cString: infoPointer.pointee.ifa_name) + let addr = pointer.pointee.ifa_addr.pointee + guard addr.sa_family == UInt8(AF_LINK) else { return nil } + var networkData: UnsafeMutablePointer? = nil + + if name.hasPrefix("en") { + networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer.self) + return [Int64(networkData?.pointee.ifi_obytes ?? 0), Int64(networkData?.pointee.ifi_ibytes ?? 0)] // upload, download + } + + return nil + } func setInterval(value: Int) {} } diff --git a/Stats/Views/PopupViewController.swift b/Stats/Views/PopupViewController.swift index ba128f6e..a1682e72 100644 --- a/Stats/Views/PopupViewController.swift +++ b/Stats/Views/PopupViewController.swift @@ -38,7 +38,7 @@ class MainViewController: NSViewController { makeHeader() - for module in modules.value { + for module in modules { module.active.subscribe(observer: self) { (value, _) in for tab in self.tabView.tabViewItems { self.tabView.removeTabViewItem(tab) @@ -53,7 +53,7 @@ class MainViewController: NSViewController { } override func viewWillAppear() { - for module in modules.value { + for module in modules { if module.tabAvailable && module.available.value && module.active.value && module.reader.availableAdditional { module.reader.startAdditional() } @@ -61,7 +61,7 @@ class MainViewController: NSViewController { } override func viewWillDisappear() { - for module in modules.value { + for module in modules { if module.tabAvailable && module.available.value && module.active.value && module.reader.availableAdditional { module.reader.stopAdditional() } @@ -70,7 +70,7 @@ class MainViewController: NSViewController { func makeHeader() { var list: [String] = [] - for module in modules.value { + for module in modules { if module.tabAvailable && module.available.value && module.active.value { list.append(module.name) @@ -124,7 +124,7 @@ class MainViewController: NSViewController { func buildSettings() -> NSMenu { let menu = NSMenu() - for module in modules.value { + for module in modules { if module.available.value { menu.addItem(module.menu) } diff --git a/Stats/libs/Extensions.swift b/Stats/libs/Extensions.swift index 4967edb9..891b8f6e 100755 --- a/Stats/libs/Extensions.swift +++ b/Stats/libs/Extensions.swift @@ -1,6 +1,6 @@ // // Extensions.swift -// Mini Stats +// Stats // // Created by Serhiy Mytrovtsiy on 29/05/2019. // Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. diff --git a/Stats/libs/Observable.swift b/Stats/libs/Observable.swift index aa7f02d2..86491ff7 100755 --- a/Stats/libs/Observable.swift +++ b/Stats/libs/Observable.swift @@ -1,6 +1,6 @@ // // Observable.swift -// Mini Stats +// Stats // // Created by Serhiy Mytrovtsiy on 29/05/2019. // Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved.