mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: moved from JSON objects of metrics to simplified strings for the Stats Remote
This commit is contained in:
@@ -12,6 +12,10 @@
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
public protocol RemoteType {
|
||||
func remote() -> Data?
|
||||
}
|
||||
|
||||
public class Remote {
|
||||
public static let shared = Remote()
|
||||
static public var host = URL(string: "http://localhost:8008")! // https://api.system-stats.com http://localhost:8008
|
||||
@@ -83,9 +87,9 @@ public class Remote {
|
||||
NotificationCenter.default.post(name: .remoteState, object: nil, userInfo: ["auth": self.isAuthorized])
|
||||
}
|
||||
|
||||
public func send(key: String, value: Codable) {
|
||||
guard self.monitoring && self.isAuthorized, let blobData = try? JSONEncoder().encode(value) else { return }
|
||||
self.ws.send(key: key, data: blobData)
|
||||
public func send(key: String, value: Any) {
|
||||
guard self.monitoring && self.isAuthorized, let v = value as? RemoteType, let data = v.remote() else { return }
|
||||
self.ws.send(key: key, data: data)
|
||||
}
|
||||
|
||||
@objc private func successLogin() {
|
||||
@@ -462,9 +466,6 @@ class WebSocketManager: NSObject {
|
||||
}
|
||||
|
||||
public func send(key: String, data: Data) {
|
||||
if key != "details" && !key.contains("CPU@") && !key.contains("GPU@") && !key.contains("RAM@") && !key.contains("Network@") && !key.contains("Sensors@") {
|
||||
return
|
||||
}
|
||||
if !self.isConnected { return }
|
||||
let message = WebSocketMessage(name: key, data: data)
|
||||
guard let messageData = try? JSONEncoder().encode(message) else { return }
|
||||
|
||||
@@ -10,7 +10,7 @@ import Cocoa
|
||||
import Kit
|
||||
import WidgetKit
|
||||
|
||||
public struct CPU_Load: Codable {
|
||||
public struct CPU_Load: Codable, RemoteType {
|
||||
var totalUsage: Double = 0
|
||||
var usagePerCore: [Double] = []
|
||||
var usageECores: Double? = nil
|
||||
@@ -19,6 +19,26 @@ public struct CPU_Load: Codable {
|
||||
var systemLoad: Double = 0
|
||||
var userLoad: Double = 0
|
||||
var idleLoad: Double = 0
|
||||
|
||||
public func remote() -> Data? {
|
||||
var string = "1,1,\(self.totalUsage),\(self.usagePerCore.count),"
|
||||
for c in self.usagePerCore {
|
||||
string += "\(c),"
|
||||
}
|
||||
string += "$"
|
||||
return string.data(using: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
public struct CPU_Frequency: Codable, RemoteType {
|
||||
var value: Double = 0
|
||||
var eCore: Double = 0
|
||||
var pCore: Double = 0
|
||||
|
||||
public func remote() -> Data? {
|
||||
let string = "1,1,\(self.value)$"
|
||||
return string.data(using: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
public struct CPU_Limit: Codable {
|
||||
|
||||
@@ -421,9 +421,8 @@ internal class Popup: PopupWrapper {
|
||||
})
|
||||
}
|
||||
|
||||
public func frequencyCallback(_ value: [Double]?) {
|
||||
public func frequencyCallback(_ value: CPU_Frequency?) {
|
||||
guard let value else { return }
|
||||
guard !value.filter({ $0 != 0 }).isEmpty else { return }
|
||||
|
||||
DispatchQueue.main.async(execute: {
|
||||
if !self.initializedFrequency {
|
||||
@@ -436,37 +435,19 @@ internal class Popup: PopupWrapper {
|
||||
}
|
||||
|
||||
if (self.window?.isVisible ?? false) || !self.initializedFrequency {
|
||||
if value.count == 1 {
|
||||
let freq = value.first ?? 0
|
||||
if freq > self.maxFreq {
|
||||
self.maxFreq = freq
|
||||
}
|
||||
self.coresFreqField?.stringValue = "\(Int(freq)) MHz"
|
||||
if let circle = self.frequencyCircle {
|
||||
circle.setValue((100*freq)/self.maxFreq)
|
||||
circle.setText("\((freq/1000).rounded(toPlaces: 2))")
|
||||
circle.toolTip = "\(localizedString("CPU frequency")): \(Int(freq)) MHz - \(((100*freq)/self.maxFreq).rounded(toPlaces: 2))%"
|
||||
}
|
||||
} else if value.count == 2 {
|
||||
let e = value.first ?? 0
|
||||
let p = value.last ?? 0
|
||||
self.eCoresFreqField?.stringValue = "\(Int(e)) MHz"
|
||||
self.pCoresFreqField?.stringValue = "\(Int(p)) MHz"
|
||||
|
||||
if let eCoreCount = SystemKit.shared.device.info.cpu?.eCores, let pCoreCount = SystemKit.shared.device.info.cpu?.pCores {
|
||||
let freq = ((e * Double(eCoreCount)) + (p * Double(pCoreCount))) / Double(eCoreCount + pCoreCount)
|
||||
if freq > self.maxFreq {
|
||||
self.maxFreq = freq
|
||||
}
|
||||
self.coresFreqField?.stringValue = "\(Int(freq)) MHz"
|
||||
if let circle = self.frequencyCircle {
|
||||
circle.setValue((100*freq)/self.maxFreq)
|
||||
circle.setText("\((freq/1000).rounded(toPlaces: 2))")
|
||||
circle.toolTip = "\(localizedString("CPU frequency")): \(Int(freq)) MHz - \(((100*freq)/self.maxFreq).rounded(toPlaces: 2))%"
|
||||
}
|
||||
}
|
||||
if value.value > self.maxFreq {
|
||||
self.maxFreq = value.value
|
||||
}
|
||||
|
||||
self.coresFreqField?.stringValue = "\(Int(value.value)) MHz"
|
||||
if let circle = self.frequencyCircle {
|
||||
circle.setValue((100*value.value)/self.maxFreq)
|
||||
circle.setText("\((value.value/1000).rounded(toPlaces: 2))")
|
||||
circle.toolTip = "\(localizedString("CPU frequency")): \(Int(value.value)) MHz - \(((100*value.value)/self.maxFreq).rounded(toPlaces: 2))%"
|
||||
}
|
||||
self.eCoresFreqField?.stringValue = "\(Int(value.eCore)) MHz"
|
||||
self.pCoresFreqField?.stringValue = "\(Int(value.pCore)) MHz"
|
||||
|
||||
self.initializedFrequency = true
|
||||
}
|
||||
})
|
||||
|
||||
@@ -292,9 +292,11 @@ public class TemperatureReader: Reader<Double> {
|
||||
}
|
||||
|
||||
// inspired by https://github.com/shank03/StatsBar/blob/e175aa71c914ce882ce2e90163f3eb18262a8e25/StatsBar/Service/IOReport.swift
|
||||
public class FrequencyReader: Reader<[Double]> {
|
||||
public class FrequencyReader: Reader<CPU_Frequency> {
|
||||
private var eCoreFreqs: [Int32] = []
|
||||
private var pCoreFreqs: [Int32] = []
|
||||
private var eCoreCount: Double = 0
|
||||
private var pCoreCount: Double = 0
|
||||
|
||||
private var channels: CFMutableDictionary? = nil
|
||||
private var subscription: IOReportSubscriptionRef? = nil
|
||||
@@ -314,6 +316,8 @@ public class FrequencyReader: Reader<[Double]> {
|
||||
public override func setup() {
|
||||
self.eCoreFreqs = SystemKit.shared.device.info.cpu?.eCoreFrequencies ?? []
|
||||
self.pCoreFreqs = SystemKit.shared.device.info.cpu?.pCoreFrequencies ?? []
|
||||
self.eCoreCount = Double(SystemKit.shared.device.info.cpu?.eCores ?? 0)
|
||||
self.pCoreCount = Double(SystemKit.shared.device.info.cpu?.pCores ?? 0)
|
||||
self.channels = self.getChannels()
|
||||
var dict: Unmanaged<CFMutableDictionary>?
|
||||
self.subscription = IOReportCreateSubscription(nil, self.channels, &dict, 0, nil)
|
||||
@@ -352,8 +356,9 @@ public class FrequencyReader: Reader<[Double]> {
|
||||
|
||||
let eFreq: Double = eCores.reduce(0, { $0 + $1 }) / Double(self.measurementCount)
|
||||
let pFreq: Double = pCores.reduce(0, { $0 + $1 }) / Double(self.measurementCount)
|
||||
let value: Double = ((eFreq * self.eCoreCount) + (pFreq * self.pCoreCount)) / (self.eCoreCount + self.pCoreCount)
|
||||
|
||||
self.callback([eFreq, pFreq])
|
||||
self.callback(CPU_Frequency(value: value, eCore: eFreq, pCore: pFreq))
|
||||
self.isReading = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +64,13 @@ public struct drive: Codable {
|
||||
public var popupState: Bool {
|
||||
Store.shared.bool(key: "Disk_\(self.uuid)_popup", defaultValue: true)
|
||||
}
|
||||
|
||||
public func remote() -> String {
|
||||
return "\(self.uuid),\(self.size),\(self.size-self.free),\(self.free),\(self.activity.read),\(self.activity.write)"
|
||||
}
|
||||
}
|
||||
|
||||
public class Disks: Codable {
|
||||
public class Disks: Codable, RemoteType {
|
||||
private var queue: DispatchQueue = DispatchQueue(label: "eu.exelban.Stats.Disk.SynchronizedArray")
|
||||
private var _array: [drive] = []
|
||||
public var array: [drive] {
|
||||
@@ -156,6 +160,18 @@ public class Disks: Codable {
|
||||
func updateSMARTData(_ idx: Int, smart: smart_t?) {
|
||||
self.array[idx].smart = smart
|
||||
}
|
||||
|
||||
public func remote() -> Data? {
|
||||
var string = "\(self.array.count),"
|
||||
for (i, v) in self.array.enumerated() {
|
||||
string += v.remote()
|
||||
if i != self.array.count {
|
||||
string += ","
|
||||
}
|
||||
}
|
||||
string += "$"
|
||||
return string.data(using: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Disk_process: Process_p, Codable {
|
||||
|
||||
@@ -52,9 +52,17 @@ public struct GPU_Info: Codable {
|
||||
self.renderUtilization = render
|
||||
self.tilerUtilization = tiler
|
||||
}
|
||||
|
||||
public func remote() -> String {
|
||||
var id = self.id
|
||||
if self.id.isEmpty {
|
||||
id = "0"
|
||||
}
|
||||
return "\(id),1,\(self.utilization ?? 0),\(self.renderUtilization ?? 0),\(self.tilerUtilization ?? 0),,"
|
||||
}
|
||||
}
|
||||
|
||||
public class GPUs: Codable {
|
||||
public class GPUs: Codable, RemoteType {
|
||||
private var queue: DispatchQueue = DispatchQueue(label: "eu.exelban.Stats.GPU.SynchronizedArray")
|
||||
|
||||
private var _list: [GPU_Info] = []
|
||||
@@ -82,6 +90,18 @@ public class GPUs: Codable {
|
||||
internal func active() -> [GPU_Info] {
|
||||
return self.list.filter{ $0.state && $0.utilization != nil }.sorted{ $0.utilization ?? 0 > $1.utilization ?? 0 }
|
||||
}
|
||||
|
||||
public func remote() -> Data? {
|
||||
var string = "\(self.list.count),"
|
||||
for (i, v) in self.list.enumerated() {
|
||||
string += v.remote()
|
||||
if i != self.list.count {
|
||||
string += ","
|
||||
}
|
||||
}
|
||||
string += "$"
|
||||
return string.data(using: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
public class GPU: Module {
|
||||
|
||||
@@ -68,7 +68,7 @@ public struct Bandwidth: Codable {
|
||||
var download: Int64 = 0
|
||||
}
|
||||
|
||||
public struct Network_Usage: Codable {
|
||||
public struct Network_Usage: Codable, RemoteType {
|
||||
var bandwidth: Bandwidth = Bandwidth()
|
||||
var total: Bandwidth = Bandwidth()
|
||||
|
||||
@@ -92,6 +92,12 @@ public struct Network_Usage: Codable {
|
||||
|
||||
self.wifiDetails.reset()
|
||||
}
|
||||
|
||||
public func remote() -> Data? {
|
||||
let addr = "\(self.laddr.v4 ?? ""),\(self.laddr.v6 ?? ""),\(self.raddr.v4 ?? ""),\(self.raddr.v6 ?? "")"
|
||||
let string = "1,\(self.interface?.BSDName ?? ""),1,\(self.bandwidth.download),\(self.bandwidth.upload),\(addr)$"
|
||||
return string.data(using: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Network_Connectivity: Codable {
|
||||
|
||||
@@ -13,7 +13,7 @@ import Cocoa
|
||||
import Kit
|
||||
import WidgetKit
|
||||
|
||||
public struct RAM_Usage: Codable {
|
||||
public struct RAM_Usage: Codable, RemoteType {
|
||||
var total: Double
|
||||
var used: Double
|
||||
var free: Double
|
||||
@@ -35,6 +35,11 @@ public struct RAM_Usage: Codable {
|
||||
public var usage: Double {
|
||||
get { Double((self.total - self.free) / self.total) }
|
||||
}
|
||||
|
||||
public func remote() -> Data? {
|
||||
let string = "\(self.total),\(self.used),\(self.pressure.level),\(self.swap.used)$"
|
||||
return string.data(using: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Swap: Codable {
|
||||
|
||||
Reference in New Issue
Block a user