summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2021-09-30 12:13:46 +0200
committerAndrej Mihajlov <and@mullvad.net>2021-10-01 13:33:07 +0200
commit3ccf307a3356349530b1a2ba53cb552e390f6dfb (patch)
tree2deae073efbdda86bed2a9eb501c9e9bcd574f56 /ios/MullvadVPN/RelayCache/RelayCacheTracker.swift
parent981e94ba407d49e328b2f41cbd1a0e35bfca506d (diff)
downloadmullvadvpn-3ccf307a3356349530b1a2ba53cb552e390f6dfb.tar.xz
mullvadvpn-3ccf307a3356349530b1a2ba53cb552e390f6dfb.zip
iOS: add background tasks
iOS 12: Use UIApplicationDelegate.performFetchWithCompletionHandler to update relays and rotate the private key. iOS 13: 1. Background refresh task to update relays once an hour. 2. Background processing task for private key rotation.
Diffstat (limited to 'ios/MullvadVPN/RelayCache/RelayCacheTracker.swift')
-rw-r--r--ios/MullvadVPN/RelayCache/RelayCacheTracker.swift83
1 files changed, 83 insertions, 0 deletions
diff --git a/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift b/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift
index 401fea19f8..6e8228e400 100644
--- a/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift
+++ b/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift
@@ -6,6 +6,7 @@
// Copyright © 2019 Mullvad VPN AB. All rights reserved.
//
+import BackgroundTasks
import Foundation
import Logging
@@ -245,3 +246,85 @@ extension RelayCache {
}
}
+
+// MARK: - Background tasks
+
+@available(iOS 13.0, *)
+extension RelayCache.Tracker {
+
+ /// Register app refresh task with scheduler.
+ func registerAppRefreshTask() {
+ let taskIdentifier = ApplicationConfiguration.appRefreshTaskIdentifier
+
+ let isRegistered = BGTaskScheduler.shared.register(forTaskWithIdentifier: taskIdentifier, using: nil) { task in
+ self.handleAppRefreshTask(task as! BGAppRefreshTask)
+ }
+
+ if isRegistered {
+ logger.debug("Registered app refresh task")
+ } else {
+ logger.error("Failed to register app refresh task")
+ }
+ }
+
+ /// Schedules app refresh task relative to the last relays update.
+ func scheduleAppRefreshTask() -> Result<(), RelayCache.Error>.Promise {
+ return self.read().flatMap { cachedRelays in
+ let beginDate = cachedRelays.updatedAt.addingTimeInterval(Self.relayUpdateInterval)
+
+ return self.submitAppRefreshTask(at: beginDate)
+ }
+ }
+
+ /// Create and submit task request to scheduler.
+ private func submitAppRefreshTask(at beginDate: Date) -> Result<(), RelayCache.Error> {
+ let taskIdentifier = ApplicationConfiguration.appRefreshTaskIdentifier
+
+ let request = BGAppRefreshTaskRequest(identifier: taskIdentifier)
+ request.earliestBeginDate = beginDate
+
+ return Result { try BGTaskScheduler.shared.submit(request) }
+ .mapError { error in
+ return .backgroundTaskScheduler(error)
+ }
+ }
+
+ /// Background task handler
+ private func handleAppRefreshTask(_ task: BGAppRefreshTask) {
+ var cancellationToken: PromiseCancellationToken?
+
+ self.logger.debug("Start app refresh task")
+
+ self.updateRelays()
+ .storeCancellationToken(in: &cancellationToken)
+ .observe { completion in
+ switch completion {
+ case .finished(.success(let fetchResult)):
+ self.logger.debug("Finished updating relays in app refresh task: \(fetchResult)")
+
+ case .finished(.failure(let error)):
+ self.logger.error(chainedError: error, message: "Failed to update relays in app refresh task")
+
+ case .cancelled:
+ self.logger.debug("App refresh task was cancelled")
+ }
+
+ task.setTaskCompleted(success: !completion.isCancelled)
+ }
+
+ task.expirationHandler = {
+ cancellationToken?.cancel()
+ }
+
+ // Schedule next refresh
+ let scheduleDate = Date(timeIntervalSinceNow: Self.relayUpdateInterval)
+
+ switch self.submitAppRefreshTask(at: scheduleDate) {
+ case .success:
+ self.logger.debug("Scheduled next app refresh task at \(scheduleDate.logFormatDate())")
+
+ case .failure(let error):
+ self.logger.error(chainedError: error, message: "Failed to schedule next app refresh task")
+ }
+ }
+}