summaryrefslogtreecommitdiff
path: root/Hutch/Networking/SystemStatusRepository.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-11 23:36:35 -0500
committerChristian Cleberg <[email protected]>2026-04-11 23:36:35 -0500
commit00cc231e9b419d27b412036d93457c2cbabe0b16 (patch)
tree6b042b802fcddcd1e03f1ae0f666965620225485 /Hutch/Networking/SystemStatusRepository.swift
parent0fde7529ceaebf1cd9baa01826d95d587023d001 (diff)
downloadhutch-00cc231e9b419d27b412036d93457c2cbabe0b16.tar.gz
hutch-00cc231e9b419d27b412036d93457c2cbabe0b16.tar.bz2
hutch-00cc231e9b419d27b412036d93457c2cbabe0b16.zip
Add SourceHut system status screen and home disruption banner
Diffstat (limited to 'Hutch/Networking/SystemStatusRepository.swift')
-rw-r--r--Hutch/Networking/SystemStatusRepository.swift57
1 files changed, 57 insertions, 0 deletions
diff --git a/Hutch/Networking/SystemStatusRepository.swift b/Hutch/Networking/SystemStatusRepository.swift
new file mode 100644
index 0000000..48c5b16
--- /dev/null
+++ b/Hutch/Networking/SystemStatusRepository.swift
@@ -0,0 +1,57 @@
+import Foundation
+
+actor SystemStatusRepository {
+ private let service: SystemStatusService
+ private let ttl: TimeInterval
+
+ private var snapshotCache: CacheEntry<SystemStatusSnapshot>?
+ private var incidentsCache: CacheEntry<[StatusIncident]>?
+
+ init(service: SystemStatusService = SystemStatusService(), ttl: TimeInterval = 10 * 60) {
+ self.service = service
+ self.ttl = ttl
+ }
+
+ func snapshot(forceRefresh: Bool = false) async throws -> SystemStatusSnapshot {
+ if let cached = snapshotCache, !forceRefresh, !cached.isExpired(ttl: ttl) {
+ return cached.value
+ }
+
+ do {
+ let snapshot = try await service.fetchSnapshot()
+ snapshotCache = CacheEntry(value: snapshot, timestamp: Date())
+ return snapshot
+ } catch {
+ if let cached = snapshotCache {
+ return cached.value
+ }
+ throw error
+ }
+ }
+
+ func recentIncidents(forceRefresh: Bool = false) async throws -> [StatusIncident] {
+ if let cached = incidentsCache, !forceRefresh, !cached.isExpired(ttl: ttl) {
+ return cached.value
+ }
+
+ do {
+ let incidents = try await service.fetchIncidentFeed()
+ incidentsCache = CacheEntry(value: incidents, timestamp: Date())
+ return incidents
+ } catch {
+ if let cached = incidentsCache {
+ return cached.value
+ }
+ throw error
+ }
+ }
+}
+
+private struct CacheEntry<Value: Sendable>: Sendable {
+ let value: Value
+ let timestamp: Date
+
+ nonisolated func isExpired(ttl: TimeInterval) -> Bool {
+ Date().timeIntervalSince(timestamp) > ttl
+ }
+}