Add ImageService with memory + disk cache

This commit is contained in:
Brendan Szymanski 2026-06-05 01:12:48 -04:00
parent 87e2e7431f
commit a58c5129fc

View file

@ -0,0 +1,50 @@
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
public actor ImageService {
private let cacheDir: URL
private let memoryCache = NSCache<NSString, NSData>()
public init(cacheDir: URL? = nil) {
let defaultCache = FileManager.default.urls(
for: .cachesDirectory, in: .userDomainMask
).first!.appendingPathComponent("luminate/images")
self.cacheDir = cacheDir ?? defaultCache
try? FileManager.default.createDirectory(at: self.cacheDir, withIntermediateDirectories: true)
}
public func loadImage(url: URL) async throws -> Data {
let key = url.absoluteString as NSString
if let cached = memoryCache.object(forKey: key) {
return cached as Data
}
let diskKey = url.absoluteString.data(using: .utf8)!.base64EncodedString()
.replacingOccurrences(of: "/", with: "_")
let diskURL = cacheDir.appendingPathComponent(diskKey)
if let data = try? Data(contentsOf: diskURL) {
memoryCache.setObject(data as NSData, forKey: key)
return data
}
let (data, _) = try await URLSession.shared.data(from: url)
let nsData = data as NSData
memoryCache.setObject(nsData, forKey: key)
try? data.write(to: diskURL)
return data
}
public func prefetch(urls: [URL]) async {
await withTaskGroup(of: Void.self) { group in
for url in urls {
group.addTask { _ = try? await self.loadImage(url: url) }
}
}
}
public func clearCache() {
memoryCache.removeAllObjects()
try? FileManager.default.removeItem(at: cacheDir)
try? FileManager.default.createDirectory(at: cacheDir, withIntermediateDirectories: true)
}
}