diff --git a/Kit/helpers.swift b/Kit/helpers.swift index 5ca2e347..59448377 100644 --- a/Kit/helpers.swift +++ b/Kit/helpers.swift @@ -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 } } diff --git a/Kit/plugins/SystemKit.swift b/Kit/plugins/SystemKit.swift index 79fa6d2c..fc0bda58 100644 --- a/Kit/plugins/SystemKit.swift +++ b/Kit/plugins/SystemKit.swift @@ -11,7 +11,7 @@ import Cocoa -public enum Platform: String { +public enum Platform: String, Codable { case intel case m1 diff --git a/Modules/Battery/main.swift b/Modules/Battery/main.swift index f77c5dc2..0f14a6cd 100644 --- a/Modules/Battery/main.swift +++ b/Modules/Battery/main.swift @@ -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 diff --git a/Modules/Battery/readers.swift b/Modules/Battery/readers.swift index 19eacf0f..31680851 100644 --- a/Modules/Battery/readers.swift +++ b/Modules/Battery/readers.swift @@ -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)) } } diff --git a/Modules/Bluetooth/main.swift b/Modules/Bluetooth/main.swift index 5bef8bfc..031a1968 100644 --- a/Modules/Bluetooth/main.swift +++ b/Modules/Bluetooth/main.swift @@ -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.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 { diff --git a/Modules/CPU/main.swift b/Modules/CPU/main.swift index 32130db3..dc7efb35 100644 --- a/Modules/CPU/main.swift +++ b/Modules/CPU/main.swift @@ -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 diff --git a/Modules/CPU/readers.swift b/Modules/CPU/readers.swift index 75b2dc75..cef48c4e 100644 --- a/Modules/CPU/readers.swift +++ b/Modules/CPU/readers.swift @@ -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 } diff --git a/Modules/Disk/main.swift b/Modules/Disk/main.swift index 4143856a..9e3c5001 100644 --- a/Modules/Disk/main.swift +++ b/Modules/Disk/main.swift @@ -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.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 - } } } } diff --git a/Modules/GPU/main.swift b/Modules/GPU/main.swift index 60f71a13..82b3a20c 100644 --- a/Modules/GPU/main.swift +++ b/Modules/GPU/main.swift @@ -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] { diff --git a/Modules/Net/main.swift b/Modules/Net/main.swift index 19c4ac68..1e3de327 100644 --- a/Modules/Net/main.swift +++ b/Modules/Net/main.swift @@ -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 } } diff --git a/Modules/Net/readers.swift b/Modules/Net/readers.swift index 514d5ec1..91d56b97 100644 --- a/Modules/Net/readers.swift +++ b/Modules/Net/readers.swift @@ -215,7 +215,7 @@ internal class UsageReader: Reader { 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 { } freeifaddrs(interfaceAddresses) - return (totalUpload, totalDownload) + return Bandwidth(upload: totalUpload, download: totalDownload) } private func readProcessBandwidth() -> Bandwidth { @@ -260,7 +260,7 @@ internal class UsageReader: Reader { 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 { _ = 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 { } } - return (totalUpload, totalDownload) + return Bandwidth(upload: totalUpload, download: totalDownload) } public func getDetails() { @@ -416,7 +416,7 @@ internal class UsageReader: Reader { } @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 { +internal class ConnectivityReader: Reader { private let variablesQueue = DispatchQueue(label: "eu.exelban.ConnectivityReaderQueue") private let identifier = UInt16.random(in: 0.. { 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 { 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() { diff --git a/Modules/RAM/main.swift b/Modules/RAM/main.swift index be5e0dcc..6d5425c1 100644 --- a/Modules/RAM/main.swift +++ b/Modules/RAM/main.swift @@ -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 diff --git a/Modules/RAM/readers.swift b/Modules/RAM/readers.swift index 897497f2..f10c948f 100644 --- a/Modules/RAM/readers.swift +++ b/Modules/RAM/readers.swift @@ -78,7 +78,7 @@ internal class UsageReader: Reader { 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)) } } diff --git a/Modules/Sensors/main.swift b/Modules/Sensors/main.swift index a606353d..b71e54bf 100644 --- a/Modules/Sensors/main.swift +++ b/Modules/Sensors/main.swift @@ -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 { diff --git a/Modules/Sensors/readers.swift b/Modules/Sensors/readers.swift index 304e6e44..aa565c14 100644 --- a/Modules/Sensors/readers.swift +++ b/Modules/Sensors/readers.swift @@ -12,21 +12,10 @@ import Cocoa import Kit -internal class SensorsReader: Reader<[Sensor_p]> { +internal class SensorsReader: Reader { 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 }) } } } diff --git a/Modules/Sensors/values.swift b/Modules/Sensors/values.swift index 98300234..86b34b21 100644 --- a/Modules/Sensors/values.swift +++ b/Modules/Sensors/values.swift @@ -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 diff --git a/SMC/smc.swift b/SMC/smc.swift index 4ae8efa4..d3cd046e 100644 --- a/SMC/smc.swift +++ b/SMC/smc.swift @@ -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 }