90 lines
3.1 KiB
Swift
90 lines
3.1 KiB
Swift
import BackgroundTasks
|
|
import Foundation
|
|
import WidgetKit
|
|
|
|
enum SmartDataRefreshScheduler {
|
|
static let taskIdentifier = "com.apt.fuelboard.smart-refresh"
|
|
|
|
static func register() {
|
|
BGTaskScheduler.shared.register(forTaskWithIdentifier: taskIdentifier, using: nil) { task in
|
|
guard let task = task as? BGAppRefreshTask else {
|
|
task.setTaskCompleted(success: false)
|
|
return
|
|
}
|
|
handle(task)
|
|
}
|
|
}
|
|
|
|
static func scheduleNextIfNeeded() {
|
|
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: taskIdentifier)
|
|
guard FuelStore.loadDataRefreshMode() == .smart else { return }
|
|
let request = BGAppRefreshTaskRequest(identifier: taskIdentifier)
|
|
request.earliestBeginDate = Date(timeIntervalSinceNow: FuelStore.smartProbeInterval)
|
|
do {
|
|
try BGTaskScheduler.shared.submit(request)
|
|
} catch {
|
|
#if DEBUG
|
|
print("SMART-REFRESH schedule failed: \(error)")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
private static func handle(_ task: BGAppRefreshTask) {
|
|
scheduleNextIfNeeded()
|
|
let refreshTask = Task {
|
|
let success = await SmartDataRefreshCoordinator.runBackgroundProbe()
|
|
task.setTaskCompleted(success: success)
|
|
}
|
|
task.expirationHandler = {
|
|
refreshTask.cancel()
|
|
}
|
|
}
|
|
}
|
|
|
|
enum SmartDataRefreshCoordinator {
|
|
@discardableResult
|
|
static func runBackgroundProbe(now: Date = Date()) async -> Bool {
|
|
guard FuelStore.loadDataRefreshMode() == .smart else { return true }
|
|
guard FuelStore.isSmartProbeDue(now: now) || FuelStore.loadStations().isEmpty else {
|
|
return true
|
|
}
|
|
FuelStore.saveLastSmartProbe(now)
|
|
guard !Task.isCancelled else { return false }
|
|
|
|
guard let latest = await FuelHistoryStore.fetchLatest() else {
|
|
return false
|
|
}
|
|
|
|
let latestDay = latest.availableTo ?? latest.date
|
|
let latestUpdated = latest.dataUpdated
|
|
let cachedDay = MirrorFuelProvider.loadDumpCache()?.day
|
|
let savedUpdated = FuelStore.loadDataUpdated()
|
|
let shouldFetchFullDump = FuelStore.loadStations().isEmpty
|
|
|| !FuelStore.isCacheFresh(now: now)
|
|
|| (latestDay != nil && latestDay != cachedDay)
|
|
|| (latestUpdated != nil && latestUpdated != savedUpdated)
|
|
|
|
guard shouldFetchFullDump, !Task.isCancelled else { return true }
|
|
|
|
do {
|
|
let fetched = try await FuelPriceProvider.active.fetchStations(
|
|
near: nil,
|
|
lng: nil,
|
|
fuel: FuelStore.loadSelectedFuel(),
|
|
radiusKM: nil
|
|
)
|
|
guard !Task.isCancelled else { return false }
|
|
FuelStore.saveStations(fetched)
|
|
FuelStore.saveLastRefresh(now)
|
|
await WatchSyncManager.shared.pushSnapshot()
|
|
if let meta = LiveChainProvider.latestMeta {
|
|
FuelStore.saveRelayMeta(meta)
|
|
}
|
|
WidgetCenter.shared.reloadAllTimelines()
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
}
|