66 lines
2.6 KiB
Swift
66 lines
2.6 KiB
Swift
import Foundation
|
|
|
|
/// Encrypted local message cache.
|
|
/// Matches Python: chat_core.py message cache (message_cache/{conv_id}.json)
|
|
enum MessageCache {
|
|
|
|
/// Save messages for a conversation (encrypted with local storage key)
|
|
static func save(email: String, convId: String, messages: [[String: Any]], cacheKey: Data?) throws {
|
|
let dir = try KeyStorage.getKeyDir(email: email).appendingPathComponent("message_cache")
|
|
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
|
|
|
let jsonData = try JSONSerialization.data(withJSONObject: messages)
|
|
|
|
let dataToWrite: Data
|
|
if let cacheKey = cacheKey {
|
|
dataToWrite = try CryptoUtils.encryptLocal(jsonData, key: cacheKey)
|
|
} else {
|
|
dataToWrite = jsonData
|
|
}
|
|
|
|
try dataToWrite.write(to: dir.appendingPathComponent("\(convId).json"), options: .completeFileProtection)
|
|
}
|
|
|
|
/// Load messages for a conversation
|
|
static func load(email: String, convId: String, cacheKey: Data?) -> [[String: Any]]? {
|
|
guard let dir = try? KeyStorage.getKeyDir(email: email) else { return nil }
|
|
let path = dir.appendingPathComponent("message_cache").appendingPathComponent("\(convId).json")
|
|
guard let raw = try? Data(contentsOf: path) else { return nil }
|
|
|
|
let jsonData: Data
|
|
if let cacheKey = cacheKey {
|
|
if let decrypted = try? CryptoUtils.decryptLocal(raw, key: cacheKey) {
|
|
jsonData = decrypted
|
|
} else {
|
|
// Plaintext fallback (migration)
|
|
jsonData = raw
|
|
}
|
|
} else {
|
|
jsonData = raw
|
|
}
|
|
|
|
return try? JSONSerialization.jsonObject(with: jsonData) as? [[String: Any]]
|
|
}
|
|
|
|
/// Search messages in a conversation
|
|
static func search(email: String, convId: String, query: String, cacheKey: Data?) -> [[String: Any]] {
|
|
guard let messages = load(email: email, convId: convId, cacheKey: cacheKey) else {
|
|
return []
|
|
}
|
|
let lowerQuery = query.lowercased()
|
|
return messages.filter { msg in
|
|
if let text = msg["text"] as? String, text.lowercased().contains(lowerQuery) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
/// Delete cache for a conversation
|
|
static func delete(email: String, convId: String) {
|
|
guard let dir = try? KeyStorage.getKeyDir(email: email) else { return }
|
|
let path = dir.appendingPathComponent("message_cache").appendingPathComponent("\(convId).json")
|
|
try? FileManager.default.removeItem(at: path)
|
|
}
|
|
}
|