summaryrefslogtreecommitdiff
path: root/Hutch/Networking/PasteService.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-05-06 20:41:49 -0500
committerChristian Cleberg <[email protected]>2026-05-06 20:41:49 -0500
commit205cf2687ce48f3d004792ff223422a86cc6bdbc (patch)
tree7edb78cede354e79aa8abd764ed9c5047e0ee168 /Hutch/Networking/PasteService.swift
parent57e4f34b4613c09beb0cb757ac2ba2b43cc04daf (diff)
downloadhutch-3.3.1.tar.gz
hutch-3.3.1.tar.bz2
hutch-3.3.1.zip
feat(cache): persist read-only API responsesv3.3.1
Add a bounded stale-while-revalidate cache at the Sourcehut API boundary with stable keys, centralized TTLs, request coalescing, payload hashing, and LRU disk pruning. Cache high-value read-only repo, build, ticket, project, profile, paste, and Home/Work Queue data while keeping mutations network-only and invalidating related prefixes after successful writes. Add focused cache tests and implementation notes.
Diffstat (limited to 'Hutch/Networking/PasteService.swift')
-rw-r--r--Hutch/Networking/PasteService.swift19
1 files changed, 15 insertions, 4 deletions
diff --git a/Hutch/Networking/PasteService.swift b/Hutch/Networking/PasteService.swift
index b9aa530..92a618e 100644
--- a/Hutch/Networking/PasteService.swift
+++ b/Hutch/Networking/PasteService.swift
@@ -109,13 +109,17 @@ final class PasteService: Sendable {
let variables = cursor.map { ["cursor": $0 as any Sendable] }
let result: PasteListResponse
if useCache, cursor == nil {
- result = try await client.executeAndCache(
+ let cached = try await client.executeCached(
service: .paste,
query: Self.listQuery,
variables: variables,
responseType: PasteListResponse.self,
- cacheKey: Self.cacheKey
+ cacheKey: APICacheKeys.pasteList(cursor: cursor),
+ resourceType: .pasteList,
+ ttl: APICacheTTLs.ticketList,
+ policy: .cacheFirstThenRefresh
)
+ result = cached.value
} else {
result = try await client.execute(
service: .paste,
@@ -127,8 +131,8 @@ final class PasteService: Sendable {
return result.pastes ?? PasteListPage(results: [], cursor: nil)
}
- func loadCachedPastes() -> PasteListPage? {
- guard let data = client.responseCache.get(forKey: Self.cacheKey) else {
+ func loadCachedPastes() async -> PasteListPage? {
+ guard let data = await client.cachedPayload(forKey: APICacheKeys.pasteList()) ?? client.responseCache.get(forKey: Self.cacheKey) else {
return nil
}
@@ -171,6 +175,7 @@ final class PasteService: Sendable {
},
responseType: CreatePasteResponse.self
)
+ await invalidatePasteCaches()
return result.create
}
@@ -181,6 +186,7 @@ final class PasteService: Sendable {
variables: ["id": id, "visibility": visibility.rawValue],
responseType: UpdatePasteResponse.self
)
+ await invalidatePasteCaches()
return result.update
}
@@ -191,6 +197,7 @@ final class PasteService: Sendable {
variables: ["id": id],
responseType: DeletePasteResponse.self
)
+ await invalidatePasteCaches()
return result.delete
}
@@ -208,6 +215,10 @@ final class PasteService: Sendable {
return (draft.filename, data)
}
}
+
+ private func invalidatePasteCaches() async {
+ await client.invalidateCache(prefix: APICacheKeys.prefix(SRHTService.paste.rawValue, "pastes"))
+ }
}
private struct PasteListResponse: Decodable, Sendable {