mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: separate disk activity reader from disk capacity reader (#468)
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import Darwin
|
||||
import os.log
|
||||
|
||||
internal class CapacityReader: Reader<DiskList> {
|
||||
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<DiskList> {
|
||||
|
||||
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<DiskList> {
|
||||
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<DiskList> {
|
||||
return parent
|
||||
}
|
||||
|
||||
private func driveStats(_ entry: io_registry_entry_t, _ diskStats: UnsafeMutablePointer<stats?>) {
|
||||
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<DiskList> {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
internal class ActivityReader: Reader<DiskList> {
|
||||
internal var disks: UnsafeMutablePointer<DiskList>? = nil
|
||||
|
||||
init(list: UnsafeMutablePointer<DiskList>?) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user