Files
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

121 lines
4.0 KiB
Swift

import Foundation
protocol SystemStatusHistoryStoring: Sendable {
func load(referenceDate: Date) async -> [SystemStatusHistoryPoint]
func append(_ point: SystemStatusHistoryPoint, referenceDate: Date) async -> [SystemStatusHistoryPoint]
}
actor SystemStatusHistoryStore: SystemStatusHistoryStoring {
static let retention: TimeInterval = 24 * 60 * 60
static let maximumSampleCount = 8_640
private let fileURL: URL
private var samples: [SystemStatusHistoryPoint] = []
private var didLoad = false
init(fileURL: URL) {
self.fileURL = fileURL
}
nonisolated static func defaultFileURL(supportDirectory: URL?) -> URL {
if let supportDirectory {
return supportDirectory.appendingPathComponent("system-status-history.json", isDirectory: false)
}
let baseDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
?? FileManager.default.temporaryDirectory
return baseDirectory
.appendingPathComponent("MacTools", isDirectory: true)
.appendingPathComponent("SystemStatus", isDirectory: true)
.appendingPathComponent("system-status-history.json", isDirectory: false)
}
func load(referenceDate: Date = Date()) async -> [SystemStatusHistoryPoint] {
if !didLoad {
samples = loadFromDisk()
didLoad = true
}
samples = Self.pruned(samples, referenceDate: referenceDate)
return samples
}
func append(_ point: SystemStatusHistoryPoint, referenceDate: Date = Date()) async -> [SystemStatusHistoryPoint] {
if !didLoad {
samples = loadFromDisk()
didLoad = true
}
samples.append(point)
samples = Self.pruned(samples, referenceDate: referenceDate)
persist(samples)
return samples
}
nonisolated static func pruned(
_ points: [SystemStatusHistoryPoint],
referenceDate: Date
) -> [SystemStatusHistoryPoint] {
let cutoff = referenceDate.timeIntervalSince1970 - retention
let recentPoints = points
.filter { $0.timestamp >= cutoff && $0.timestamp <= referenceDate.timeIntervalSince1970 + 60 }
.sorted { $0.timestamp < $1.timestamp }
guard recentPoints.count > maximumSampleCount else {
return recentPoints
}
return Array(recentPoints.suffix(maximumSampleCount))
}
private func loadFromDisk() -> [SystemStatusHistoryPoint] {
guard let data = try? Data(contentsOf: fileURL), !data.isEmpty else {
return []
}
guard
let document = try? JSONDecoder().decode(SystemStatusHistoryDocument.self, from: data),
document.schemaVersion == 1
else {
return []
}
return document.samples
}
private func persist(_ samples: [SystemStatusHistoryPoint]) {
let document = SystemStatusHistoryDocument(schemaVersion: 1, samples: samples)
guard let data = try? JSONEncoder.systemStatusHistoryEncoder.encode(document) else {
return
}
do {
try FileManager.default.createDirectory(
at: fileURL.deletingLastPathComponent(),
withIntermediateDirectories: true
)
let temporaryURL = fileURL
.deletingLastPathComponent()
.appendingPathComponent(".\(fileURL.lastPathComponent).tmp", isDirectory: false)
try data.write(to: temporaryURL, options: [.atomic])
if FileManager.default.fileExists(atPath: fileURL.path) {
_ = try FileManager.default.replaceItemAt(fileURL, withItemAt: temporaryURL)
} else {
try FileManager.default.moveItem(at: temporaryURL, to: fileURL)
}
} catch {
return
}
}
}
private extension JSONEncoder {
static var systemStatusHistoryEncoder: JSONEncoder {
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys]
return encoder
}
}