Download this file
| 1 | import Foundation |
| 2 | |
| 3 | // In-memory LRU for decrypted attachment bytes (videos, files), keyed by blob |
| 4 | // id — so replaying a clip doesn't re-download and re-decrypt it. RAM only, by |
| 5 | // design: the E2E posture is that decrypted content never lands on disk unless |
| 6 | // the member deliberately saves it. The native twin of the web's blobURLs |
| 7 | // object-URL cache. Byte-capped, oldest-used evicted first. |
| 8 | @MainActor |
| 9 | public final class BlobDataCache { |
| 10 | public static let shared = BlobDataCache() |
| 11 | |
| 12 | private var entries: [(id: String, data: Data)] = [] // front = most recent |
| 13 | private let maxBytes = 256 << 20 // ~256 MB of clips |
| 14 | |
| 15 | public func get(_ id: String) -> Data? { |
| 16 | guard let i = entries.firstIndex(where: { $0.id == id }) else { return nil } |
| 17 | let e = entries.remove(at: i) |
| 18 | entries.insert(e, at: 0) // refresh recency |
| 19 | return e.data |
| 20 | } |
| 21 | |
| 22 | public func put(_ id: String, _ data: Data) { |
| 23 | entries.removeAll { $0.id == id } |
| 24 | entries.insert((id, data), at: 0) |
| 25 | var total = entries.reduce(0) { $0 + $1.data.count } |
| 26 | while total > maxBytes, let last = entries.popLast() { |
| 27 | total -= last.data.count |
| 28 | } |
| 29 | } |
| 30 | } |
| 31 | |