diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2021-09-30 12:13:46 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2021-10-01 13:33:07 +0200 |
| commit | 3ccf307a3356349530b1a2ba53cb552e390f6dfb (patch) | |
| tree | 2deae073efbdda86bed2a9eb501c9e9bcd574f56 /ios/MullvadVPN/RelayCache/RelayCacheTracker.swift | |
| parent | 981e94ba407d49e328b2f41cbd1a0e35bfca506d (diff) | |
| download | mullvadvpn-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.swift | 83 |
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") + } + } +} |
