64 lines
2.4 KiB
Swift
64 lines
2.4 KiB
Swift
import Foundation
|
|
|
|
final class MessageStore {
|
|
private let messagesKey = "kasztelan.messages"
|
|
private let lastIDKey = "kasztelan.messages.lastID"
|
|
private let installedAtKey = "kasztelan.installation.timestamp"
|
|
|
|
var messages: [KasztelanMessage] {
|
|
guard let data = UserDefaults.standard.data(forKey: messagesKey),
|
|
let values = try? JSONDecoder().decode([KasztelanMessage].self, from: data) else { return [] }
|
|
return values.filter(isFromThisInstallation).sorted { $0.id > $1.id }
|
|
}
|
|
|
|
var lastServerID: Int { UserDefaults.standard.integer(forKey: lastIDKey) }
|
|
|
|
@discardableResult
|
|
func merge(_ incoming: [KasztelanMessage]) -> [KasztelanMessage] {
|
|
var saved = messages
|
|
var ids = Set(saved.map(\.id))
|
|
let previousLast = lastServerID
|
|
let added = incoming.filter { message in
|
|
guard message.id > 0,
|
|
isFromThisInstallation(message),
|
|
!message.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return false }
|
|
return ids.insert(message.id).inserted
|
|
}
|
|
saved.append(contentsOf: added)
|
|
saved.sort { $0.id > $1.id }
|
|
saved = Array(saved.prefix(100))
|
|
persist(saved, lastID: max(previousLast, incoming.map(\.id).max() ?? 0))
|
|
return added.filter { $0.id > previousLast }.sorted { $0.id > $1.id }
|
|
}
|
|
|
|
func delete(id: Int) {
|
|
persist(messages.filter { $0.id != id }, lastID: lastServerID)
|
|
}
|
|
|
|
func clear() {
|
|
UserDefaults.standard.removeObject(forKey: messagesKey)
|
|
UserDefaults.standard.removeObject(forKey: lastIDKey)
|
|
}
|
|
|
|
private func persist(_ messages: [KasztelanMessage], lastID: Int) {
|
|
if let data = try? JSONEncoder().encode(messages) {
|
|
UserDefaults.standard.set(data, forKey: messagesKey)
|
|
}
|
|
UserDefaults.standard.set(lastID, forKey: lastIDKey)
|
|
}
|
|
|
|
private var installedAt: Int {
|
|
let saved = UserDefaults.standard.integer(forKey: installedAtKey)
|
|
if saved > 0 { return saved }
|
|
let created = (try? FileManager.default.attributesOfItem(atPath: NSHomeDirectory())[.creationDate] as? Date)
|
|
?? Date()
|
|
let timestamp = Int(created.timeIntervalSince1970)
|
|
UserDefaults.standard.set(timestamp, forKey: installedAtKey)
|
|
return timestamp
|
|
}
|
|
|
|
private func isFromThisInstallation(_ message: KasztelanMessage) -> Bool {
|
|
message.sentAt >= installedAt
|
|
}
|
|
}
|