mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: moved all reader's values to the Codable protocol
This commit is contained in:
@@ -95,16 +95,33 @@ public protocol KeyValue_p {
|
||||
var additional: Any? { get }
|
||||
}
|
||||
|
||||
public struct KeyValue_t: KeyValue_p {
|
||||
public struct KeyValue_t: KeyValue_p, Codable {
|
||||
public let key: String
|
||||
public let value: String
|
||||
public let additional: Any?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case key, value
|
||||
}
|
||||
|
||||
public init(key: String, value: String, additional: Any? = nil) {
|
||||
self.key = key
|
||||
self.value = value
|
||||
self.additional = additional
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.key = try container.decode(String.self, forKey: .key)
|
||||
self.value = try container.decode(String.self, forKey: .value)
|
||||
self.additional = nil
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(key, forKey: .key)
|
||||
try container.encode(value, forKey: .value)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Units {
|
||||
@@ -560,19 +577,26 @@ public func removeNotification(_ id: String) {
|
||||
center.removeDeliveredNotifications(withIdentifiers: [id])
|
||||
}
|
||||
|
||||
public struct TopProcess {
|
||||
public struct TopProcess: Codable {
|
||||
public var pid: Int
|
||||
public var command: String
|
||||
public var name: String?
|
||||
public var usage: Double
|
||||
public var icon: NSImage?
|
||||
|
||||
public init(pid: Int, command: String, name: String?, usage: Double, icon: NSImage?) {
|
||||
public var icon: NSImage? {
|
||||
get {
|
||||
if let app = NSRunningApplication(processIdentifier: pid_t(self.pid) ) {
|
||||
return app.icon
|
||||
}
|
||||
return Constants.defaultProcessIcon
|
||||
}
|
||||
}
|
||||
|
||||
public init(pid: Int, command: String, name: String?, usage: Double) {
|
||||
self.pid = pid
|
||||
self.command = command
|
||||
self.name = name
|
||||
self.usage = usage
|
||||
self.icon = icon != nil ? icon : Constants.defaultProcessIcon
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
public enum Platform: String {
|
||||
public enum Platform: String, Codable {
|
||||
case intel
|
||||
|
||||
case m1
|
||||
|
||||
@@ -13,7 +13,7 @@ import Cocoa
|
||||
import Kit
|
||||
import IOKit.ps
|
||||
|
||||
struct Battery_Usage: value_t {
|
||||
struct Battery_Usage: value_t, Codable {
|
||||
var powerSource: String = ""
|
||||
var state: String? = nil
|
||||
var isCharged: Bool = false
|
||||
|
||||
@@ -221,13 +221,11 @@ public class ProcessReader: Reader<[TopProcess]> {
|
||||
}
|
||||
|
||||
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))
|
||||
processes.append(TopProcess(pid: pid, command: command, name: name, usage: usage))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import Foundation
|
||||
import Kit
|
||||
import CoreBluetooth
|
||||
|
||||
public struct BLEDevice {
|
||||
public struct BLEDevice: Codable {
|
||||
let address: String
|
||||
var name: String
|
||||
var uuid: UUID?
|
||||
@@ -24,7 +24,7 @@ public struct BLEDevice {
|
||||
var isConnected: Bool = false
|
||||
var isPaired: Bool = false
|
||||
|
||||
var peripheral: CBPeripheral?
|
||||
var peripheral: CBPeripheral? = nil
|
||||
var isPeripheralInitialized: Bool = false
|
||||
|
||||
var id: String {
|
||||
@@ -38,6 +38,42 @@ public struct BLEDevice {
|
||||
return Store.shared.bool(key: "ble_\(self.id)", defaultValue: false)
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case address, name, uuid, RSSI, batteryLevel, isConnected, isPaired
|
||||
}
|
||||
|
||||
init(address: String, name: String, uuid: UUID?, RSSI: Int?, batteryLevel: [KeyValue_t], isConnected: Bool, isPaired: Bool) {
|
||||
self.address = address
|
||||
self.name = name
|
||||
self.uuid = uuid
|
||||
self.RSSI = RSSI
|
||||
self.batteryLevel = batteryLevel
|
||||
self.isConnected = isConnected
|
||||
self.isPaired = isPaired
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.address = try container.decode(String.self, forKey: .address)
|
||||
self.name = try container.decode(String.self, forKey: .name)
|
||||
self.uuid = try? container.decode(UUID.self, forKey: .uuid)
|
||||
self.RSSI = try? container.decode(Int.self, forKey: .RSSI)
|
||||
self.batteryLevel = try container.decode(Array<KeyValue_t>.self, forKey: .batteryLevel)
|
||||
self.isConnected = try container.decode(Bool.self, forKey: .isConnected)
|
||||
self.isPaired = try container.decode(Bool.self, forKey: .isPaired)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(address, forKey: .address)
|
||||
try container.encode(name, forKey: .name)
|
||||
try container.encode(uuid, forKey: .uuid)
|
||||
try container.encode(RSSI, forKey: .RSSI)
|
||||
try container.encode(batteryLevel, forKey: .batteryLevel)
|
||||
try container.encode(isConnected, forKey: .isConnected)
|
||||
try container.encode(isPaired, forKey: .isPaired)
|
||||
}
|
||||
}
|
||||
|
||||
public class Bluetooth: Module {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import Cocoa
|
||||
import Kit
|
||||
|
||||
public struct CPU_Load: value_t {
|
||||
public struct CPU_Load: value_t, Codable {
|
||||
var totalUsage: Double = 0
|
||||
var usagePerCore: [Double] = []
|
||||
var usageECores: Double? = nil
|
||||
@@ -26,7 +26,7 @@ public struct CPU_Load: value_t {
|
||||
}
|
||||
}
|
||||
|
||||
public struct CPU_Limit {
|
||||
public struct CPU_Limit: Codable {
|
||||
var scheduler: Int = 0
|
||||
var cpus: Int = 0
|
||||
var speed: Int = 0
|
||||
|
||||
@@ -232,13 +232,11 @@ public class ProcessReader: Reader<[TopProcess]> {
|
||||
let usage = Double(usageString.replacingOccurrences(of: ",", with: ".")) ?? 0
|
||||
|
||||
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))
|
||||
processes.append(TopProcess(pid: pid, command: command, name: name, usage: usage))
|
||||
}
|
||||
|
||||
if index == self.numberOfProcesses { stop = true }
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import Cocoa
|
||||
import Kit
|
||||
|
||||
public struct stats {
|
||||
public struct stats: Codable {
|
||||
var read: Int64 = 0
|
||||
var write: Int64 = 0
|
||||
|
||||
@@ -20,12 +20,12 @@ public struct stats {
|
||||
var writeBytes: Int64 = 0
|
||||
}
|
||||
|
||||
public struct smart_t {
|
||||
public struct smart_t: Codable {
|
||||
var temperature: Int = 0
|
||||
var life: Int = 0
|
||||
}
|
||||
|
||||
public struct drive {
|
||||
public struct drive: Codable {
|
||||
var parent: io_object_t = 0
|
||||
|
||||
var mediaName: String = ""
|
||||
@@ -46,9 +46,25 @@ public struct drive {
|
||||
var smart: smart_t? = nil
|
||||
}
|
||||
|
||||
public class Disks {
|
||||
fileprivate let queue = DispatchQueue(label: "eu.exelban.Stats.Disk.SynchronizedArray", attributes: .concurrent)
|
||||
fileprivate var array = [drive]()
|
||||
public class Disks: Codable {
|
||||
private var queue: DispatchQueue = DispatchQueue(label: "eu.exelban.Stats.Disk.SynchronizedArray", attributes: .concurrent)
|
||||
private var array: [drive] = []
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case array
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.array = try container.decode(Array<drive>.self, forKey: CodingKeys.array)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(array, forKey: .array)
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
public var count: Int {
|
||||
var result = 0
|
||||
@@ -140,14 +156,19 @@ public class Disks {
|
||||
}
|
||||
}
|
||||
|
||||
public struct Disk_process: IOProcess_p {
|
||||
public struct Disk_process: IOProcess_p, Codable {
|
||||
private var base: DataSizeBase {
|
||||
DataSizeBase(rawValue: Store.shared.string(key: "\(Disk.name)_base", defaultValue: "byte")) ?? .byte
|
||||
}
|
||||
|
||||
public var pid: Int32
|
||||
public var name: String
|
||||
public var icon: NSImage = Constants.defaultProcessIcon
|
||||
public var icon: NSImage {
|
||||
if let app = NSRunningApplication(processIdentifier: self.pid) {
|
||||
return app.icon ?? Constants.defaultProcessIcon
|
||||
}
|
||||
return Constants.defaultProcessIcon
|
||||
}
|
||||
|
||||
var read: Int
|
||||
var write: Int
|
||||
@@ -169,9 +190,6 @@ public struct Disk_process: IOProcess_p {
|
||||
if let name = app.localizedName {
|
||||
self.name = name
|
||||
}
|
||||
if let icon = app.icon {
|
||||
self.icon = icon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public enum GPU_types: GPU_type {
|
||||
case discrete = "d"
|
||||
}
|
||||
|
||||
public struct GPU_Info {
|
||||
public struct GPU_Info: Codable {
|
||||
public let id: String
|
||||
public let type: GPU_type
|
||||
|
||||
@@ -50,7 +50,7 @@ public struct GPU_Info {
|
||||
}
|
||||
}
|
||||
|
||||
public struct GPUs: value_t {
|
||||
public struct GPUs: value_t, Codable {
|
||||
public var list: [GPU_Info] = []
|
||||
|
||||
internal func active() -> [GPU_Info] {
|
||||
|
||||
@@ -13,25 +13,25 @@ import Cocoa
|
||||
import Kit
|
||||
import SystemConfiguration
|
||||
|
||||
public enum Network_t: String {
|
||||
public enum Network_t: String, Codable {
|
||||
case wifi
|
||||
case ethernet
|
||||
case bluetooth
|
||||
case other
|
||||
}
|
||||
|
||||
public struct Network_interface {
|
||||
public struct Network_interface: Codable {
|
||||
var displayName: String = ""
|
||||
var BSDName: String = ""
|
||||
var address: String = ""
|
||||
}
|
||||
|
||||
public struct Network_addr {
|
||||
public struct Network_addr: Codable {
|
||||
var v4: String? = nil
|
||||
var v6: String? = nil
|
||||
}
|
||||
|
||||
public struct Network_wifi {
|
||||
public struct Network_wifi: Codable {
|
||||
var countryCode: String? = nil
|
||||
var ssid: String? = nil
|
||||
var bssid: String? = nil
|
||||
@@ -61,9 +61,14 @@ public struct Network_wifi {
|
||||
}
|
||||
}
|
||||
|
||||
public struct Network_Usage: value_t {
|
||||
var bandwidth: Bandwidth = (0, 0)
|
||||
var total: Bandwidth = (0, 0)
|
||||
public struct Bandwidth: Codable {
|
||||
var upload: Int64 = 0
|
||||
var download: Int64 = 0
|
||||
}
|
||||
|
||||
public struct Network_Usage: value_t, Codable {
|
||||
var bandwidth: Bandwidth = Bandwidth()
|
||||
var total: Bandwidth = Bandwidth()
|
||||
|
||||
var laddr: String? = nil // local ip
|
||||
var raddr: Network_addr = Network_addr() // remote ip
|
||||
@@ -75,7 +80,7 @@ public struct Network_Usage: value_t {
|
||||
var wifiDetails: Network_wifi = Network_wifi()
|
||||
|
||||
mutating func reset() {
|
||||
self.bandwidth = (0, 0)
|
||||
self.bandwidth = Bandwidth()
|
||||
|
||||
self.laddr = nil
|
||||
self.raddr = Network_addr()
|
||||
@@ -89,13 +94,24 @@ public struct Network_Usage: value_t {
|
||||
public var widgetValue: Double = 0
|
||||
}
|
||||
|
||||
public struct Network_Process {
|
||||
public struct Network_Connectivity: Codable {
|
||||
var status: Bool = false
|
||||
}
|
||||
|
||||
public struct Network_Process: Codable {
|
||||
var time: Date = Date()
|
||||
var name: String = ""
|
||||
var pid: String = ""
|
||||
var download: Int = 0
|
||||
var upload: Int = 0
|
||||
var icon: NSImage? = nil
|
||||
var icon: NSImage {
|
||||
get {
|
||||
if let pid = pid_t(self.pid), let app = NSRunningApplication(processIdentifier: pid) {
|
||||
return app.icon ?? Constants.defaultProcessIcon
|
||||
}
|
||||
return Constants.defaultProcessIcon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Network: Module {
|
||||
@@ -167,7 +183,7 @@ public class Network: Module {
|
||||
self.settingsView.ICMPHostCallback = { [unowned self] isDisabled in
|
||||
if isDisabled {
|
||||
self.popupView.resetConnectivityView()
|
||||
self.connectivityCallback(false)
|
||||
self.connectivityCallback(Network_Connectivity(status: false))
|
||||
}
|
||||
}
|
||||
self.settingsView.publicIPRefreshIntervalCallback = { [unowned self] in
|
||||
@@ -222,14 +238,14 @@ public class Network: Module {
|
||||
}
|
||||
}
|
||||
|
||||
private func connectivityCallback(_ raw: Bool?) {
|
||||
private func connectivityCallback(_ raw: Network_Connectivity?) {
|
||||
guard let value = raw, self.enabled else { return }
|
||||
|
||||
self.popupView.connectivityCallback(value)
|
||||
self.popupView.connectivityCallback(value.status)
|
||||
|
||||
self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
|
||||
switch w.item {
|
||||
case let widget as StateWidget: widget.setValue(value)
|
||||
case let widget as StateWidget: widget.setValue(value.status)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ internal class UsageReader: Reader<Network_Usage> {
|
||||
var totalUpload: Int64 = 0
|
||||
var totalDownload: Int64 = 0
|
||||
guard getifaddrs(&interfaceAddresses) == 0 else {
|
||||
return (0, 0)
|
||||
return Bandwidth()
|
||||
}
|
||||
|
||||
var pointer = interfaceAddresses
|
||||
@@ -237,7 +237,7 @@ internal class UsageReader: Reader<Network_Usage> {
|
||||
}
|
||||
freeifaddrs(interfaceAddresses)
|
||||
|
||||
return (totalUpload, totalDownload)
|
||||
return Bandwidth(upload: totalUpload, download: totalDownload)
|
||||
}
|
||||
|
||||
private func readProcessBandwidth() -> Bandwidth {
|
||||
@@ -260,7 +260,7 @@ internal class UsageReader: Reader<Network_Usage> {
|
||||
try task.run()
|
||||
} catch let err {
|
||||
error("read bandwidth from processes: \(err)", log: self.log)
|
||||
return (0, 0)
|
||||
return Bandwidth()
|
||||
}
|
||||
|
||||
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
|
||||
@@ -269,7 +269,7 @@ internal class UsageReader: Reader<Network_Usage> {
|
||||
_ = String(decoding: errorData, as: UTF8.self)
|
||||
|
||||
if output.isEmpty {
|
||||
return (0, 0)
|
||||
return Bandwidth()
|
||||
}
|
||||
|
||||
var totalUpload: Int64 = 0
|
||||
@@ -294,7 +294,7 @@ internal class UsageReader: Reader<Network_Usage> {
|
||||
}
|
||||
}
|
||||
|
||||
return (totalUpload, totalDownload)
|
||||
return Bandwidth(upload: totalUpload, download: totalDownload)
|
||||
}
|
||||
|
||||
public func getDetails() {
|
||||
@@ -416,7 +416,7 @@ internal class UsageReader: Reader<Network_Usage> {
|
||||
}
|
||||
|
||||
@objc func resetTotalNetworkUsage() {
|
||||
self.usage.total = (0, 0)
|
||||
self.usage.total = Bandwidth()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,10 +492,8 @@ public class ProcessReader: Reader<[Network_Process]> {
|
||||
}
|
||||
if let app = NSRunningApplication(processIdentifier: pid_t(process.pid) ?? 0) {
|
||||
process.name = app.localizedName ?? nameArray.dropLast().joined(separator: ".")
|
||||
process.icon = app.icon != nil ? app.icon : Constants.defaultProcessIcon
|
||||
} else {
|
||||
process.name = nameArray.dropLast().joined(separator: ".")
|
||||
process.icon = Constants.defaultProcessIcon
|
||||
}
|
||||
|
||||
if process.name == "" {
|
||||
@@ -533,7 +531,7 @@ public class ProcessReader: Reader<[Network_Process]> {
|
||||
upload = 0
|
||||
}
|
||||
|
||||
processes.append(Network_Process(time: time, name: p.name, pid: p.pid, download: download, upload: upload, icon: p.icon))
|
||||
processes.append(Network_Process(time: time, name: p.name, pid: p.pid, download: download, upload: upload))
|
||||
}
|
||||
}
|
||||
self.previous = list
|
||||
@@ -566,7 +564,7 @@ internal class ConnectivityReaderWrapper {
|
||||
}
|
||||
|
||||
// inspired by https://github.com/samiyr/SwiftyPing
|
||||
internal class ConnectivityReader: Reader<Bool> {
|
||||
internal class ConnectivityReader: Reader<Network_Connectivity> {
|
||||
private let variablesQueue = DispatchQueue(label: "eu.exelban.ConnectivityReaderQueue")
|
||||
|
||||
private let identifier = UInt16.random(in: 0..<UInt16.max)
|
||||
@@ -582,6 +580,8 @@ internal class ConnectivityReader: Reader<Bool> {
|
||||
private var socket: CFSocket?
|
||||
private var socketSource: CFRunLoopSource?
|
||||
|
||||
private var wrapper: Network_Connectivity = Network_Connectivity(status: false)
|
||||
|
||||
private var _status: Bool? = nil
|
||||
private var status: Bool? {
|
||||
get {
|
||||
@@ -672,7 +672,11 @@ internal class ConnectivityReader: Reader<Bool> {
|
||||
if error != .success {
|
||||
self.socketCallback(data: nil, error: error)
|
||||
}
|
||||
self.callback(self.status)
|
||||
|
||||
if let v = self.status {
|
||||
self.wrapper.status = v
|
||||
self.callback(self.wrapper)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func timeoutCallback() {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import Cocoa
|
||||
import Kit
|
||||
|
||||
public struct RAM_Usage: value_t {
|
||||
public struct RAM_Usage: value_t, Codable {
|
||||
var total: Double
|
||||
var used: Double
|
||||
var free: Double
|
||||
@@ -26,7 +26,7 @@ public struct RAM_Usage: value_t {
|
||||
var cache: Double
|
||||
var pressure: Double
|
||||
|
||||
var pressureLevel: DispatchSource.MemoryPressureEvent
|
||||
var rawPressureLevel: UInt
|
||||
var swap: Swap
|
||||
|
||||
public var widgetValue: Double {
|
||||
@@ -40,9 +40,13 @@ public struct RAM_Usage: value_t {
|
||||
return Double((self.total - self.free) / self.total)
|
||||
}
|
||||
}
|
||||
|
||||
public var pressureLevel: DispatchSource.MemoryPressureEvent {
|
||||
DispatchSource.MemoryPressureEvent(rawValue: self.rawPressureLevel)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Swap {
|
||||
public struct Swap: Codable {
|
||||
var total: Double
|
||||
var used: Double
|
||||
var free: Double
|
||||
|
||||
@@ -78,7 +78,7 @@ internal class UsageReader: Reader<RAM_Usage> {
|
||||
cache: purgeable + external,
|
||||
pressure: 100.0 * (wired + compressed) / self.totalSize,
|
||||
|
||||
pressureLevel: DispatchSource.MemoryPressureEvent(rawValue: UInt(pressureLevel)),
|
||||
rawPressureLevel: UInt(pressureLevel),
|
||||
|
||||
swap: Swap(
|
||||
total: Double(swap.xsu_total),
|
||||
@@ -189,12 +189,10 @@ public class ProcessReader: Reader<[TopProcess]> {
|
||||
}
|
||||
|
||||
var name: String = command
|
||||
var icon: NSImage? = nil
|
||||
if let app = NSRunningApplication(processIdentifier: pid_t(pid) ) {
|
||||
name = app.localizedName ?? command
|
||||
icon = app.icon
|
||||
}
|
||||
|
||||
return TopProcess(pid: pid, command: command, name: name, usage: usage * Double(1024 * 1024), icon: icon)
|
||||
return TopProcess(pid: pid, command: command, name: name, usage: usage * Double(1024 * 1024))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class Sensors: Module {
|
||||
|
||||
public init() {
|
||||
self.sensorsReader = SensorsReader()
|
||||
self.settingsView = Settings("Sensors", list: self.sensorsReader.list)
|
||||
self.settingsView = Settings("Sensors", list: self.sensorsReader.list.sensors)
|
||||
self.popupView = Popup()
|
||||
|
||||
super.init(
|
||||
@@ -32,7 +32,7 @@ public class Sensors: Module {
|
||||
)
|
||||
guard self.available else { return }
|
||||
|
||||
self.popupView.setup(self.sensorsReader.list)
|
||||
self.popupView.setup(self.sensorsReader.list.sensors)
|
||||
|
||||
self.settingsView.callback = { [unowned self] in
|
||||
self.sensorsReader.read()
|
||||
@@ -44,8 +44,8 @@ public class Sensors: Module {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
self.sensorsReader.HIDCallback()
|
||||
DispatchQueue.main.async {
|
||||
self.popupView.setup(self.sensorsReader.list)
|
||||
self.settingsView.setList(list: self.sensorsReader.list)
|
||||
self.popupView.setup(self.sensorsReader.list.sensors)
|
||||
self.settingsView.setList(list: self.sensorsReader.list.sensors)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,8 +53,8 @@ public class Sensors: Module {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
self.sensorsReader.unknownCallback()
|
||||
DispatchQueue.main.async {
|
||||
self.popupView.setup(self.sensorsReader.list)
|
||||
self.settingsView.setList(list: self.sensorsReader.list)
|
||||
self.popupView.setup(self.sensorsReader.list.sensors)
|
||||
self.settingsView.setList(list: self.sensorsReader.list.sensors)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class Sensors: Module {
|
||||
public override func willTerminate() {
|
||||
guard SMCHelper.shared.isActive() else { return }
|
||||
|
||||
self.sensorsReader.list.filter({ $0 is Fan }).forEach { (s: Sensor_p) in
|
||||
self.sensorsReader.list.sensors.filter({ $0 is Fan }).forEach { (s: Sensor_p) in
|
||||
if let f = s as? Fan, let mode = f.customMode {
|
||||
if mode != .automatic {
|
||||
SMCHelper.shared.setFanMode(f.id, mode: FanMode.automatic.rawValue)
|
||||
@@ -82,16 +82,16 @@ public class Sensors: Module {
|
||||
}
|
||||
|
||||
public override func isAvailable() -> Bool {
|
||||
return !self.sensorsReader.list.isEmpty
|
||||
return !self.sensorsReader.list.sensors.isEmpty
|
||||
}
|
||||
|
||||
private func checkIfNoSensorsEnabled() {
|
||||
if self.sensorsReader.list.filter({ $0.state }).isEmpty {
|
||||
if self.sensorsReader.list.sensors.filter({ $0.state }).isEmpty {
|
||||
NotificationCenter.default.post(name: .toggleModule, object: nil, userInfo: ["module": self.config.name, "state": false])
|
||||
}
|
||||
}
|
||||
|
||||
private func usageCallback(_ raw: [Sensor_p]?) {
|
||||
private func usageCallback(_ raw: Sensors_List?) {
|
||||
guard let value = raw, self.enabled else {
|
||||
return
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public class Sensors: Module {
|
||||
var list: [Stack_t] = []
|
||||
var flatList: [[ColorValue]] = []
|
||||
|
||||
value.forEach { (s: Sensor_p) in
|
||||
value.sensors.forEach { (s: Sensor_p) in
|
||||
if s.state {
|
||||
var value = s.formattedMiniValue
|
||||
if let f = s as? Fan {
|
||||
@@ -112,7 +112,7 @@ public class Sensors: Module {
|
||||
}
|
||||
}
|
||||
|
||||
self.popupView.usageCallback(value)
|
||||
self.popupView.usageCallback(value.sensors)
|
||||
|
||||
self.menuBar.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
|
||||
switch w.item {
|
||||
|
||||
@@ -12,21 +12,10 @@
|
||||
import Cocoa
|
||||
import Kit
|
||||
|
||||
internal class SensorsReader: Reader<[Sensor_p]> {
|
||||
internal class SensorsReader: Reader<Sensors_List> {
|
||||
static let HIDtypes: [SensorType] = [.temperature, .voltage]
|
||||
|
||||
private let listQueue = DispatchQueue(label: "listQueue")
|
||||
internal var listData: [Sensor_p] = []
|
||||
internal var list: [Sensor_p] {
|
||||
get {
|
||||
self.listQueue.sync{self.listData}
|
||||
}
|
||||
set(newValue) {
|
||||
self.listQueue.sync {
|
||||
self.listData = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
internal var list: Sensors_List = Sensors_List()
|
||||
|
||||
private var lastRead: Date = Date()
|
||||
private let firstRead: Date = Date()
|
||||
@@ -39,7 +28,7 @@ internal class SensorsReader: Reader<[Sensor_p]> {
|
||||
init() {
|
||||
self.unknownSensorsState = Store.shared.bool(key: "Sensors_unknown", defaultValue: false)
|
||||
super.init()
|
||||
self.list = self.sensors()
|
||||
self.list.sensors = self.sensors()
|
||||
}
|
||||
|
||||
private func sensors() -> [Sensor_p] {
|
||||
@@ -126,15 +115,15 @@ internal class SensorsReader: Reader<[Sensor_p]> {
|
||||
}
|
||||
|
||||
public override func read() {
|
||||
for i in self.list.indices {
|
||||
guard self.list[i].group != .hid && !self.list[i].isComputed else { continue }
|
||||
if !self.unknownSensorsState && self.list[i].group == .unknown { continue }
|
||||
self.list[i].value = SMC.shared.getValue(self.list[i].key) ?? 0
|
||||
for i in self.list.sensors.indices {
|
||||
guard self.list.sensors[i].group != .hid && !self.list.sensors[i].isComputed else { continue }
|
||||
if !self.unknownSensorsState && self.list.sensors[i].group == .unknown { continue }
|
||||
self.list.sensors[i].value = SMC.shared.getValue(self.list.sensors[i].key) ?? 0
|
||||
}
|
||||
|
||||
var cpuSensors = self.list.filter({ $0.group == .CPU && $0.type == .temperature && $0.average }).map{ $0.value }
|
||||
var gpuSensors = self.list.filter({ $0.group == .GPU && $0.type == .temperature && $0.average }).map{ $0.value }
|
||||
let fanSensors = self.list.filter({ $0.type == .fan && !$0.isComputed })
|
||||
var cpuSensors = self.list.sensors.filter({ $0.group == .CPU && $0.type == .temperature && $0.average }).map{ $0.value }
|
||||
var gpuSensors = self.list.sensors.filter({ $0.group == .GPU && $0.type == .temperature && $0.average }).map{ $0.value }
|
||||
let fanSensors = self.list.sensors.filter({ $0.type == .fan && !$0.isComputed })
|
||||
|
||||
#if arch(arm64)
|
||||
if self.HIDState {
|
||||
@@ -145,23 +134,23 @@ internal class SensorsReader: Reader<[Sensor_p]> {
|
||||
return
|
||||
}
|
||||
|
||||
if let idx = self.list.firstIndex(where: { $0.group == .hid && $0.key == key }) {
|
||||
self.list[idx].value = value
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.group == .hid && $0.key == key }) {
|
||||
self.list.sensors[idx].value = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpuSensors += self.list.filter({ $0.key.hasPrefix("pACC MTR Temp") || $0.key.hasPrefix("eACC MTR Temp") }).map{ $0.value }
|
||||
gpuSensors += self.list.filter({ $0.key.hasPrefix("GPU MTR Temp") }).map{ $0.value }
|
||||
cpuSensors += self.list.sensors.filter({ $0.key.hasPrefix("pACC MTR Temp") || $0.key.hasPrefix("eACC MTR Temp") }).map{ $0.value }
|
||||
gpuSensors += self.list.sensors.filter({ $0.key.hasPrefix("GPU MTR Temp") }).map{ $0.value }
|
||||
|
||||
let socSensors = list.filter({ $0.key.hasPrefix("SOC MTR Temp") }).map{ $0.value }
|
||||
let socSensors = self.list.sensors.filter({ $0.key.hasPrefix("SOC MTR Temp") }).map{ $0.value }
|
||||
if !socSensors.isEmpty {
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "Average SOC" }) {
|
||||
self.list[idx].value = socSensors.reduce(0, +) / Double(socSensors.count)
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "Average SOC" }) {
|
||||
self.list.sensors[idx].value = socSensors.reduce(0, +) / Double(socSensors.count)
|
||||
}
|
||||
if let max = socSensors.max() {
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "Hottest SOC" }) {
|
||||
self.list[idx].value = max
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "Hottest SOC" }) {
|
||||
self.list.sensors[idx].value = max
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,46 +158,46 @@ internal class SensorsReader: Reader<[Sensor_p]> {
|
||||
#endif
|
||||
|
||||
if !cpuSensors.isEmpty {
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "Average CPU" }) {
|
||||
self.list[idx].value = cpuSensors.reduce(0, +) / Double(cpuSensors.count)
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "Average CPU" }) {
|
||||
self.list.sensors[idx].value = cpuSensors.reduce(0, +) / Double(cpuSensors.count)
|
||||
}
|
||||
if let max = cpuSensors.max() {
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "Hottest CPU" }) {
|
||||
self.list[idx].value = max
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "Hottest CPU" }) {
|
||||
self.list.sensors[idx].value = max
|
||||
}
|
||||
}
|
||||
}
|
||||
if !gpuSensors.isEmpty {
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "Average GPU" }) {
|
||||
self.list[idx].value = gpuSensors.reduce(0, +) / Double(gpuSensors.count)
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "Average GPU" }) {
|
||||
self.list.sensors[idx].value = gpuSensors.reduce(0, +) / Double(gpuSensors.count)
|
||||
}
|
||||
if let max = gpuSensors.max() {
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "Hottest GPU" }) {
|
||||
self.list[idx].value = max
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "Hottest GPU" }) {
|
||||
self.list.sensors[idx].value = max
|
||||
}
|
||||
}
|
||||
}
|
||||
if !fanSensors.isEmpty && fanSensors.count > 1 {
|
||||
if let f = fanSensors.max(by: { $0.value < $1.value }) as? Fan {
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "Fastest Fan" }) {
|
||||
if var fan = self.list[idx] as? Fan {
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "Fastest Fan" }) {
|
||||
if var fan = self.list.sensors[idx] as? Fan {
|
||||
fan.value = f.value
|
||||
fan.minSpeed = f.minSpeed
|
||||
fan.maxSpeed = f.maxSpeed
|
||||
self.list[idx] = fan
|
||||
self.list.sensors[idx] = fan
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let PSTRSensor = self.list.first(where: { $0.key == "PSTR"}), PSTRSensor.value > 0 {
|
||||
if let PSTRSensor = self.list.sensors.first(where: { $0.key == "PSTR"}), PSTRSensor.value > 0 {
|
||||
let sinceLastRead = Date().timeIntervalSince(self.lastRead)
|
||||
let sinceFirstRead = Date().timeIntervalSince(self.firstRead)
|
||||
|
||||
if let totalIdx = self.list.firstIndex(where: {$0.key == "Total System Consumption"}), sinceLastRead > 0 {
|
||||
self.list[totalIdx].value += PSTRSensor.value * sinceLastRead / 3600
|
||||
if let avgIdx = self.list.firstIndex(where: {$0.key == "Average System Total"}), sinceFirstRead > 0 {
|
||||
self.list[avgIdx].value = self.list[totalIdx].value * 3600 / sinceFirstRead
|
||||
if let totalIdx = self.list.sensors.firstIndex(where: {$0.key == "Total System Consumption"}), sinceLastRead > 0 {
|
||||
self.list.sensors[totalIdx].value += PSTRSensor.value * sinceLastRead / 3600
|
||||
if let avgIdx = self.list.sensors.firstIndex(where: {$0.key == "Average System Total"}), sinceFirstRead > 0 {
|
||||
self.list.sensors[avgIdx].value = self.list.sensors[totalIdx].value * 3600 / sinceFirstRead
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,12 +205,12 @@ internal class SensorsReader: Reader<[Sensor_p]> {
|
||||
}
|
||||
|
||||
// cut off low dc in voltage
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "VD0R" }), self.list[idx].value < 0.4 {
|
||||
self.list[idx].value = 0
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "VD0R" }), self.list.sensors[idx].value < 0.4 {
|
||||
self.list.sensors[idx].value = 0
|
||||
}
|
||||
// cut off low dc in current
|
||||
if let idx = self.list.firstIndex(where: { $0.key == "ID0R" }), self.list[idx].value < 0.05 {
|
||||
self.list[idx].value = 0
|
||||
if let idx = self.list.sensors.firstIndex(where: { $0.key == "ID0R" }), self.list.sensors[idx].value < 0.05 {
|
||||
self.list.sensors[idx].value = 0
|
||||
}
|
||||
|
||||
self.callback(self.list)
|
||||
@@ -447,9 +436,9 @@ extension SensorsReader {
|
||||
|
||||
public func HIDCallback() {
|
||||
if self.HIDState {
|
||||
self.list += self.initHIDSensors()
|
||||
self.list.sensors += self.initHIDSensors()
|
||||
} else {
|
||||
self.list = self.list.filter({ $0.group != .hid })
|
||||
self.list.sensors = self.list.sensors.filter({ $0.group != .hid })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import Kit
|
||||
import Cocoa
|
||||
|
||||
internal enum SensorGroup: String {
|
||||
public enum SensorGroup: String, Codable {
|
||||
case CPU = "CPU"
|
||||
case GPU = "GPU"
|
||||
case system = "Systems"
|
||||
@@ -21,7 +21,7 @@ internal enum SensorGroup: String {
|
||||
case unknown = "Unknown"
|
||||
}
|
||||
|
||||
internal enum SensorType: String {
|
||||
public enum SensorType: String, Codable {
|
||||
case temperature = "Temperature"
|
||||
case voltage = "Voltage"
|
||||
case current = "Current"
|
||||
@@ -30,7 +30,7 @@ internal enum SensorType: String {
|
||||
case fan = "Fans"
|
||||
}
|
||||
|
||||
internal protocol Sensor_p {
|
||||
public protocol Sensor_p {
|
||||
var key: String { get }
|
||||
var name: String { get }
|
||||
var value: Double { get set }
|
||||
@@ -49,19 +49,92 @@ internal protocol Sensor_p {
|
||||
var formattedPopupValue: String { get }
|
||||
}
|
||||
|
||||
internal struct Sensor: Sensor_p {
|
||||
var key: String
|
||||
var name: String
|
||||
public struct Sensors_List: Codable {
|
||||
private var queue: DispatchQueue = DispatchQueue(label: "eu.exelban.Stats.Sensors.SynchronizedArray", attributes: .concurrent)
|
||||
|
||||
var value: Double = 0
|
||||
private var list: [Sensor_p] = []
|
||||
public var sensors: [Sensor_p] {
|
||||
get {
|
||||
self.queue.sync{self.list}
|
||||
}
|
||||
set(newValue) {
|
||||
self.queue.sync {
|
||||
self.list = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var group: SensorGroup
|
||||
var type: SensorType
|
||||
var platforms: [Platform]
|
||||
var isComputed: Bool = false
|
||||
var average: Bool = false
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case sensors
|
||||
}
|
||||
|
||||
var unit: String {
|
||||
public init() {}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
let wrappers = sensors.map { Sensor_w($0) }
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(wrappers, forKey: .sensors)
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let wrappers = try container.decode([Sensor_w].self, forKey: .sensors)
|
||||
self.sensors = wrappers.map { $0.sensor }
|
||||
}
|
||||
}
|
||||
|
||||
public struct Sensor_w: Codable {
|
||||
let sensor: Sensor_p
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case base, payload
|
||||
}
|
||||
|
||||
private enum Typ: Int, Codable {
|
||||
case sensor
|
||||
case fan
|
||||
}
|
||||
|
||||
init(_ sensor: Sensor_p) {
|
||||
self.sensor = sensor
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let base = try container.decode(Typ.self, forKey: .base)
|
||||
switch base {
|
||||
case .sensor: self.sensor = try container.decode(Sensor.self, forKey: .payload)
|
||||
case .fan: self.sensor = try container.decode(Fan.self, forKey: .payload)
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
switch sensor {
|
||||
case let payload as Sensor:
|
||||
try container.encode(Typ.sensor, forKey: .base)
|
||||
try container.encode(payload, forKey: .payload)
|
||||
case let payload as Fan:
|
||||
try container.encode(Typ.fan, forKey: .base)
|
||||
try container.encode(payload, forKey: .payload)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct Sensor: Sensor_p, Codable {
|
||||
public var key: String
|
||||
public var name: String
|
||||
|
||||
public var value: Double = 0
|
||||
|
||||
public var group: SensorGroup
|
||||
public var type: SensorType
|
||||
public var platforms: [Platform]
|
||||
public var isComputed: Bool = false
|
||||
public var average: Bool = false
|
||||
|
||||
public var unit: String {
|
||||
get {
|
||||
switch self.type {
|
||||
case .temperature:
|
||||
@@ -80,7 +153,7 @@ internal struct Sensor: Sensor_p {
|
||||
}
|
||||
}
|
||||
|
||||
var formattedValue: String {
|
||||
public var formattedValue: String {
|
||||
get {
|
||||
switch self.type {
|
||||
case .temperature:
|
||||
@@ -99,7 +172,7 @@ internal struct Sensor: Sensor_p {
|
||||
}
|
||||
}
|
||||
}
|
||||
var formattedPopupValue: String {
|
||||
public var formattedPopupValue: String {
|
||||
get {
|
||||
switch self.type {
|
||||
case .temperature:
|
||||
@@ -118,7 +191,7 @@ internal struct Sensor: Sensor_p {
|
||||
}
|
||||
}
|
||||
}
|
||||
var formattedMiniValue: String {
|
||||
public var formattedMiniValue: String {
|
||||
get {
|
||||
switch self.type {
|
||||
case .temperature:
|
||||
@@ -132,14 +205,14 @@ internal struct Sensor: Sensor_p {
|
||||
}
|
||||
}
|
||||
|
||||
var state: Bool {
|
||||
public var state: Bool {
|
||||
Store.shared.bool(key: "sensor_\(self.key)", defaultValue: false)
|
||||
}
|
||||
var popupState: Bool {
|
||||
public var popupState: Bool {
|
||||
Store.shared.bool(key: "sensor_\(self.key)_popup", defaultValue: true)
|
||||
}
|
||||
|
||||
func copy() -> Sensor {
|
||||
public func copy() -> Sensor {
|
||||
Sensor(
|
||||
key: self.key,
|
||||
name: self.name,
|
||||
@@ -152,48 +225,48 @@ internal struct Sensor: Sensor_p {
|
||||
}
|
||||
}
|
||||
|
||||
internal struct Fan: Sensor_p {
|
||||
let id: Int
|
||||
var key: String
|
||||
var name: String
|
||||
var minSpeed: Double
|
||||
var maxSpeed: Double
|
||||
var value: Double
|
||||
var mode: FanMode
|
||||
public struct Fan: Sensor_p, Codable {
|
||||
public let id: Int
|
||||
public var key: String
|
||||
public var name: String
|
||||
public var minSpeed: Double
|
||||
public var maxSpeed: Double
|
||||
public var value: Double
|
||||
public var mode: FanMode
|
||||
|
||||
var percentage: Int {
|
||||
public var percentage: Int {
|
||||
if self.value != 0 && self.maxSpeed != 0 && self.value != 1 && self.maxSpeed != 1 {
|
||||
return (100*Int(self.value)) / Int(self.maxSpeed)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var group: SensorGroup = .sensor
|
||||
var type: SensorType = .fan
|
||||
var platforms: [Platform] = Platform.all
|
||||
var isIntelOnly: Bool = false
|
||||
var isComputed: Bool = false
|
||||
var average: Bool = false
|
||||
var unit: String = "RPM"
|
||||
public var group: SensorGroup = .sensor
|
||||
public var type: SensorType = .fan
|
||||
public var platforms: [Platform] = Platform.all
|
||||
public var isIntelOnly: Bool = false
|
||||
public var isComputed: Bool = false
|
||||
public var average: Bool = false
|
||||
public var unit: String = "RPM"
|
||||
|
||||
var formattedValue: String {
|
||||
public var formattedValue: String {
|
||||
"\(Int(value)) RPM"
|
||||
}
|
||||
var formattedMiniValue: String {
|
||||
public var formattedMiniValue: String {
|
||||
"\(Int(value))"
|
||||
}
|
||||
var formattedPopupValue: String {
|
||||
public var formattedPopupValue: String {
|
||||
"\(Int(value)) RPM"
|
||||
}
|
||||
|
||||
var state: Bool {
|
||||
public var state: Bool {
|
||||
Store.shared.bool(key: "sensor_\(self.key)", defaultValue: false)
|
||||
}
|
||||
var popupState: Bool {
|
||||
public var popupState: Bool {
|
||||
Store.shared.bool(key: "sensor_\(self.key)_popup", defaultValue: true)
|
||||
}
|
||||
|
||||
var customSpeed: Int? {
|
||||
public var customSpeed: Int? {
|
||||
get {
|
||||
if !Store.shared.exist(key: "fan_\(self.id)_speed") {
|
||||
return nil
|
||||
@@ -208,7 +281,7 @@ internal struct Fan: Sensor_p {
|
||||
}
|
||||
}
|
||||
}
|
||||
var customMode: FanMode? {
|
||||
public var customMode: FanMode? {
|
||||
get {
|
||||
if !Store.shared.exist(key: "fan_\(self.id)_mode") {
|
||||
return nil
|
||||
|
||||
@@ -42,7 +42,7 @@ internal enum SMCKeys: UInt8 {
|
||||
case readVers = 12
|
||||
}
|
||||
|
||||
public enum FanMode: Int {
|
||||
public enum FanMode: Int, Codable {
|
||||
case automatic = 0
|
||||
case forced = 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user