feat: rewritten Battery top processes reader (#781)

This commit is contained in:
Serhiy Mytrovtsiy
2022-01-22 16:37:46 +01:00
parent 252274eaf9
commit ca00510030

View File

@@ -142,99 +142,74 @@ internal class UsageReader: Reader<Battery_Usage> {
}
public class ProcessReader: Reader<[TopProcess]> {
private let title: String = "Battery"
private var task: Process = Process()
private var initialized: Bool = false
private var paused: Bool = false
private var initRead: Bool = false
private var numberOfProcesses: Int {
get {
return Store.shared.int(key: "\(self.title)_processes", defaultValue: 8)
return Store.shared.int(key: "Battery_processes", defaultValue: 8)
}
}
public override func setup() {
self.popup = true
let pipe = Pipe()
self.task.standardOutput = pipe
self.task.launchPath = "/usr/bin/top"
self.task.arguments = ["-o", "power", "-n", "\(self.numberOfProcesses)", "-stats", "pid,command,power"]
pipe.fileHandleForReading.readabilityHandler = { (fileHandle) -> Void in
let output = String(decoding: fileHandle.availableData, as: UTF8.self)
var processes: [TopProcess] = []
output.enumerateLines { (line, _) -> Void in
if line.matches("^\\d* +.+ \\d*.?\\d*$") {
var str = line.trimmingCharacters(in: .whitespaces)
if self.paused {
return
}
let pidString = str.findAndCrop(pattern: "^\\d+")
let usageString = str.findAndCrop(pattern: " +[0-9]+.*[0-9]*$")
let command = str.trimmingCharacters(in: .whitespaces)
let pid = Int(pidString) ?? 0
guard let usage = Double(usageString.filter("01234567890.".contains)) else {
return
}
var name: String? = nil
var icon: NSImage? = nil
if let app = NSRunningApplication(processIdentifier: pid_t(pid) ) {
name = app.localizedName ?? nil
icon = app.icon
}
processes.append(TopProcess(pid: pid, command: command, name: name, usage: usage, icon: icon))
}
}
if !processes.isEmpty {
self.callback(processes.prefix(self.numberOfProcesses).reversed().reversed())
}
if !self.initRead {
self.pause()
self.initRead = true
}
}
}
public override func start() {
if !self.initialized {
self.task.launch()
self.initialized = true
public override func read() {
if self.numberOfProcesses == 0 {
return
}
self.initRead = true
if !self.task.isRunning {
do {
try self.task.run()
} catch let error {
debug("run Battery process reader \(error)", log: self.log)
let task = Process()
task.launchPath = "/bin/ps"
task.launchPath = "/usr/bin/top"
task.arguments = ["-o", "power", "-l", "2", "-n", "\(self.numberOfProcesses)", "-stats", "pid,command,power"]
let outputPipe = Pipe()
defer {
outputPipe.fileHandleForReading.closeFile()
}
task.standardOutput = outputPipe
do {
try task.run()
} catch let err {
error("error read ps: \(err.localizedDescription)", log: self.log)
return
}
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
if outputData.isEmpty {
return
}
let output = String(decoding: outputData.advanced(by: outputData.count/2), as: UTF8.self)
if output.isEmpty {
return
}
var processes: [TopProcess] = []
output.enumerateLines { (line, _) -> Void in
if line.matches("^\\d+ *[^(\\d)]*\\d+\\.*\\d* *$") {
var str = line.trimmingCharacters(in: .whitespaces)
let pidString = str.findAndCrop(pattern: "^\\d+")
let usageString = str.findAndCrop(pattern: " +[0-9]+.*[0-9]*$")
let command = str.trimmingCharacters(in: .whitespaces)
let pid = Int(pidString) ?? 0
guard let usage = Double(usageString.filter("01234567890.".contains)) else {
return
}
var name: String? = nil
var icon: NSImage? = nil
if let app = NSRunningApplication(processIdentifier: pid_t(pid) ) {
name = app.localizedName ?? nil
icon = app.icon
}
processes.append(TopProcess(pid: pid, command: command, name: name, usage: usage, icon: icon))
}
} else if self.paused {
self.paused = !self.task.resume()
}
}
public override func pause() {
if self.task.isRunning && !self.paused {
self.paused = self.task.suspend()
}
}
public override func stop() {
if self.task.isRunning && !self.paused {
self.paused = self.task.suspend()
}
self.callback(processes.suffix(self.numberOfProcesses).sorted(by: { $0.usage > $1.usage }))
}
}