From 1268891845a180dbbe86b5303a34270b8d696ffb Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Sat, 15 May 2021 11:37:18 +0200 Subject: [PATCH] feat: separate disk activity reader from disk capacity reader (#468) --- Modules/Disk/main.swift | 16 +++++--- Modules/Disk/popup.swift | 14 +++---- Modules/Disk/readers.swift | 81 ++++++++++++++++++++++---------------- 3 files changed, 63 insertions(+), 48 deletions(-) diff --git a/Modules/Disk/main.swift b/Modules/Disk/main.swift index 91f80db6..4b35715b 100644 --- a/Modules/Disk/main.swift +++ b/Modules/Disk/main.swift @@ -42,7 +42,7 @@ struct drive { var size: Int64 = 1 var free: Int64 = 0 - var stats: stats? = nil + var activity: stats = stats() } struct DiskList: value_t { @@ -87,6 +87,7 @@ struct DiskList: value_t { public class Disk: Module { private let popupView: Popup = Popup() + private var activityReader: ActivityReader? = nil private var capacityReader: CapacityReader? = nil private var settingsView: Settings private var selectedDisk: String = "" @@ -101,6 +102,7 @@ public class Disk: Module { guard self.available else { return } self.capacityReader = CapacityReader() + self.activityReader = ActivityReader(list: &self.capacityReader!.disks) self.selectedDisk = Store.shared.string(key: "\(self.config.name)_disk", defaultValue: self.selectedDisk) self.capacityReader?.callbackHandler = { [unowned self] value in @@ -110,6 +112,10 @@ public class Disk: Module { self.readyHandler() } + self.activityReader?.callbackHandler = { [unowned self] value in + self.capacityCallback(value) + } + self.settingsView.selectedDiskHandler = { [unowned self] value in self.selectedDisk = value self.capacityReader?.read() @@ -117,13 +123,13 @@ public class Disk: Module { self.settingsView.callback = { [unowned self] in self.capacityReader?.read() } - self.settingsView.setInterval = { [unowned self] value in - self.capacityReader?.setInterval(value) - } if let reader = self.capacityReader { self.addReader(reader) } + if let reader = self.activityReader { + self.addReader(reader) + } } public override func widgetDidSet(_ type: widget_t) { @@ -159,7 +165,7 @@ public class Disk: Module { case let widget as Mini: widget.setValue(percentage) case let widget as BarChart: widget.setValue([percentage]) case let widget as MemoryWidget: widget.setValue((DiskSize(free).getReadableMemory(), DiskSize(usedSpace).getReadableMemory())) - case let widget as SpeedWidget: widget.setValue(upload: d.stats?.write ?? 0, download: d.stats?.read ?? 0) + case let widget as SpeedWidget: widget.setValue(upload: d.activity.write, download: d.activity.read) default: break } } diff --git a/Modules/Disk/popup.swift b/Modules/Disk/popup.swift index 60876450..8e96cf0c 100644 --- a/Modules/Disk/popup.swift +++ b/Modules/Disk/popup.swift @@ -35,7 +35,7 @@ internal class Popup: NSView, Popup_p { value.list.reversed().forEach { (drive: drive) in if let disk = self.list[drive.mediaName] { - disk.update(free: drive.free, read: drive.stats?.read, write: drive.stats?.write) + disk.update(free: drive.free, read: drive.activity.read, write: drive.activity.write) } else { let disk = DiskView( NSRect( @@ -102,7 +102,7 @@ internal class DiskView: NSView { self.layer?.backgroundColor = isDarkMode ? NSColor(hexString: "#111111", alpha: 0.25).cgColor : NSColor(hexString: "#f5f5f5", alpha: 1).cgColor } - public func update(free: Int64, read: Int64?, write: Int64?) { + public func update(free: Int64, read: Int64, write: Int64) { self.nameAndBarView.update(free: free, read: read, write: write) self.legendView.update(free: free) } @@ -213,7 +213,7 @@ internal class DiskNameAndBarView: NSView { self.addSubview(view) } - public func update(free: Int64, read: Int64?, write: Int64?) { + public func update(free: Int64, read: Int64, write: Int64) { if (self.window?.isVisible ?? false) || !self.ready { if self.usedBarSpace != nil { let percentage = CGFloat(self.size - free) / CGFloat(self.size) @@ -221,12 +221,8 @@ internal class DiskNameAndBarView: NSView { self.usedBarSpace?.setFrameSize(NSSize(width: width, height: self.usedBarSpace!.frame.height)) } - if read != nil { - self.readState?.layer?.backgroundColor = read != 0 ? NSColor.systemBlue.cgColor : NSColor.lightGray.withAlphaComponent(0.75).cgColor - } - if write != nil { - self.writeState?.layer?.backgroundColor = write != 0 ? NSColor.systemRed.cgColor : NSColor.lightGray.withAlphaComponent(0.75).cgColor - } + self.readState?.layer?.backgroundColor = read != 0 ? NSColor.systemBlue.cgColor : NSColor.lightGray.withAlphaComponent(0.75).cgColor + self.writeState?.layer?.backgroundColor = write != 0 ? NSColor.systemRed.cgColor : NSColor.lightGray.withAlphaComponent(0.75).cgColor self.ready = true } diff --git a/Modules/Disk/readers.swift b/Modules/Disk/readers.swift index e10b22bc..502a5a8e 100644 --- a/Modules/Disk/readers.swift +++ b/Modules/Disk/readers.swift @@ -17,7 +17,7 @@ import Darwin import os.log internal class CapacityReader: Reader { - private var disks: DiskList = DiskList() + internal var disks: DiskList = DiskList() public override func read() { let keys: [URLResourceKey] = [.volumeNameKey] @@ -46,7 +46,6 @@ internal class CapacityReader: Reader { if let path = self.disks.list[idx].path { self.disks.list[idx].free = self.freeDiskSpaceInBytes(path) - self.driveStats(self.disks.list[idx].parent, &self.disks.list[idx].stats) } } continue @@ -145,7 +144,6 @@ internal class CapacityReader: Reader { let partitionLevel = d.BSDName.filter { "0"..."9" ~= $0 }.count if let parent = self.getDeviceIOParent(DADiskCopyIOMedia(disk), level: Int(partitionLevel)) { d.parent = parent - self.driveStats(parent, &d.stats) } return d @@ -169,37 +167,6 @@ internal class CapacityReader: Reader { return parent } - private func driveStats(_ entry: io_registry_entry_t, _ diskStats: UnsafeMutablePointer) { - guard let props = getIOProperties(entry) else { - return - } - - if let statistics = props.object(forKey: "Statistics") as? NSDictionary { - if diskStats.pointee == nil { - diskStats.initialize(to: stats()) - } - - let readBytes = statistics.object(forKey: "Bytes (Read)") as? Int64 ?? 0 - let writeBytes = statistics.object(forKey: "Bytes (Write)") as? Int64 ?? 0 - - if diskStats.pointee?.readBytes != 0 { - diskStats.pointee?.read = readBytes - (diskStats.pointee?.readBytes ?? 0) - } - if diskStats.pointee?.writeBytes != 0 { - diskStats.pointee?.write = writeBytes - (diskStats.pointee?.writeBytes ?? 0) - } - - diskStats.pointee?.readBytes = readBytes - diskStats.pointee?.writeBytes = writeBytes - diskStats.pointee?.readOperations = statistics.object(forKey: "Operations (Read)") as? Int64 ?? 0 - diskStats.pointee?.writeOperations = statistics.object(forKey: "Operations (Read)") as? Int64 ?? 0 - diskStats.pointee?.readTime = statistics.object(forKey: "Total Time (Read)") as? Int64 ?? 0 - diskStats.pointee?.writeTime = statistics.object(forKey: "Total Time (Read)") as? Int64 ?? 0 - } - - return - } - private func freeDiskSpaceInBytes(_ path: URL) -> Int64 { do { if let url = URL(string: path.absoluteString) { @@ -224,3 +191,49 @@ internal class CapacityReader: Reader { return 0 } } + +internal class ActivityReader: Reader { + internal var disks: UnsafeMutablePointer? = nil + + init(list: UnsafeMutablePointer?) { + self.disks = list + super.init() + } + + override func setup() { + setInterval(1) + } + + public override func read() { + guard let disks = self.disks else { + return + } + + for (i, d) in disks.pointee.list.enumerated() { + guard let props = getIOProperties(d.parent) else { + return + } + + if let statistics = props.object(forKey: "Statistics") as? NSDictionary { + let readBytes = statistics.object(forKey: "Bytes (Read)") as? Int64 ?? 0 + let writeBytes = statistics.object(forKey: "Bytes (Write)") as? Int64 ?? 0 + + if disks.pointee.list[i].activity.readBytes != 0 { + disks.pointee.list[i].activity.read = readBytes - disks.pointee.list[i].activity.readBytes + } + if disks.pointee.list[i].activity.writeBytes != 0 { + disks.pointee.list[i].activity.write = writeBytes - disks.pointee.list[i].activity.writeBytes + } + + disks.pointee.list[i].activity.readBytes = readBytes + disks.pointee.list[i].activity.writeBytes = writeBytes + disks.pointee.list[i].activity.readOperations = statistics.object(forKey: "Operations (Read)") as? Int64 ?? 0 + disks.pointee.list[i].activity.writeOperations = statistics.object(forKey: "Operations (Read)") as? Int64 ?? 0 + disks.pointee.list[i].activity.readTime = statistics.object(forKey: "Total Time (Read)") as? Int64 ?? 0 + disks.pointee.list[i].activity.writeTime = statistics.object(forKey: "Total Time (Read)") as? Int64 ?? 0 + } + } + + self.callback(disks.pointee) + } +}