import Foundation import os /// Последний удачный ответ API. struct MarketSnapshot: Codable, Sendable { let date: Date let thumbs: [SymbolThumb] let histories: [String: [Double]] } /// Дисковый кэш снимка рынка в контейнере App Group. /// /// Офлайн-фолбэк: без сети виджет показывает последние реальные котировки /// с честной меткой времени, а не фиктивные данные. struct MarketSnapshotCache: Sendable { private let fileURL: URL? private static let logger = Logger(subsystem: AppGroup.id, category: "snapshot-cache") init() { fileURL = AppGroup.cachesURL?.appendingPathComponent("market-snapshot.json") } func load() -> MarketSnapshot? { guard let fileURL, let data = try? Data(contentsOf: fileURL) else { return nil } do { return try JSONDecoder().decode(MarketSnapshot.self, from: data) } catch { Self.logger.error("Кэш повреждён: \(String(describing: error), privacy: .public)") return nil } } func save(_ snapshot: MarketSnapshot) { guard let fileURL else { return } do { try FileManager.default.createDirectory( at: fileURL.deletingLastPathComponent(), withIntermediateDirectories: true ) try JSONEncoder().encode(snapshot).write(to: fileURL, options: .atomic) } catch { Self.logger.error("Кэш не сохранён: \(String(describing: error), privacy: .public)") } } }