diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-12-13 10:19:43 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-12-13 14:42:27 +0100 |
| commit | 00a0ec2adcfdd7c15c25f0a1bfeb9554d85ba17a (patch) | |
| tree | 30e0b33ed4b47c6d040e9a006da984a1fb663dd4 /ios/MullvadVPN | |
| parent | 800c01bf3d521f23b919e7d5bb0c0a2cf386ec01 (diff) | |
| download | mullvadvpn-00a0ec2adcfdd7c15c25f0a1bfeb9554d85ba17a.tar.xz mullvadvpn-00a0ec2adcfdd7c15c25f0a1bfeb9554d85ba17a.zip | |
Periodically update device data while capping it at 1 update per minute
Diffstat (limited to 'ios/MullvadVPN')
| -rw-r--r-- | ios/MullvadVPN/AccountDataThrottling.swift | 2 | ||||
| -rw-r--r-- | ios/MullvadVPN/DeviceDataThrottling.swift | 55 | ||||
| -rw-r--r-- | ios/MullvadVPN/SceneDelegate.swift | 38 | ||||
| -rw-r--r-- | ios/MullvadVPN/TunnelManager/TunnelManager.swift | 12 |
4 files changed, 87 insertions, 20 deletions
diff --git a/ios/MullvadVPN/AccountDataThrottling.swift b/ios/MullvadVPN/AccountDataThrottling.swift index f6093beeb2..3f8ae0daf4 100644 --- a/ios/MullvadVPN/AccountDataThrottling.swift +++ b/ios/MullvadVPN/AccountDataThrottling.swift @@ -66,7 +66,7 @@ struct AccountDataThrottling { switch comparisonResult { case .orderedAscending, .orderedSame: - lastUpdate = Date() + lastUpdate = now tunnelManager.updateAccountData() case .orderedDescending: diff --git a/ios/MullvadVPN/DeviceDataThrottling.swift b/ios/MullvadVPN/DeviceDataThrottling.swift new file mode 100644 index 0000000000..cb30b130ff --- /dev/null +++ b/ios/MullvadVPN/DeviceDataThrottling.swift @@ -0,0 +1,55 @@ +// +// DeviceDataThrottling.swift +// MullvadVPN +// +// Created by pronebird on 13/12/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +/// Struct used for throttling UI calls to update device data via tunnel manager. +struct DeviceDataThrottling { + /// Default cooldown interval between requests. + private static let defaultWaitInterval: TimeInterval = 60 + + let tunnelManager: TunnelManager + private(set) var lastUpdate: Date? + + init(tunnelManager: TunnelManager) { + self.tunnelManager = tunnelManager + } + + mutating func requestUpdate(forceUpdate: Bool) { + guard tunnelManager.deviceState.isLoggedIn else { + return + } + + let now = Date() + + guard !forceUpdate else { + startUpdate(now: now) + return + } + + let nextUpdateAfter = lastUpdate?.addingTimeInterval(Self.defaultWaitInterval) + let comparisonResult = nextUpdateAfter?.compare(now) ?? .orderedAscending + + switch comparisonResult { + case .orderedAscending, .orderedSame: + startUpdate(now: now) + + case .orderedDescending: + break + } + } + + mutating func reset() { + lastUpdate = nil + } + + private mutating func startUpdate(now: Date) { + lastUpdate = now + tunnelManager.updateDeviceData() + } +} diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift index 26b29c3805..1f3838b2ae 100644 --- a/ios/MullvadVPN/SceneDelegate.swift +++ b/ios/MullvadVPN/SceneDelegate.swift @@ -38,7 +38,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe private var connectController: ConnectViewController? private weak var settingsNavController: SettingsNavigationController? private var lastLoginAction: LoginAction? - private lazy var accountDataThrottling = AccountDataThrottling(tunnelManager: tunnelManager) + + private var accountDataThrottling: AccountDataThrottling? + private var deviceDataThrottling: DeviceDataThrottling? private var outOfTimeTimer: Timer? @@ -92,6 +94,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe isSceneConfigured = true + accountDataThrottling = AccountDataThrottling(tunnelManager: tunnelManager) + deviceDataThrottling = DeviceDataThrottling(tunnelManager: tunnelManager) + rootContainer.delegate = self window?.rootViewController = rootContainer @@ -107,7 +112,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe relayCacheTracker.addObserver(self) NotificationManager.shared.delegate = self - accountDataThrottling.requestUpdate(condition: .always) + refreshDeviceAndAccountData(forceUpdate: true) } private func setShowsPrivacyOverlay(_ showOverlay: Bool) { @@ -120,6 +125,21 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe } } + private func refreshDeviceAndAccountData(forceUpdate: Bool) { + let condition: AccountDataThrottling.Condition = + settingsNavController == nil && !forceUpdate + ? .whenCloseToExpiryAndBeyond + : .always + + accountDataThrottling?.requestUpdate(condition: condition) + deviceDataThrottling?.requestUpdate(forceUpdate: forceUpdate) + } + + private func resetDeviceAndAccountDataThrottling() { + accountDataThrottling?.reset() + deviceDataThrottling?.reset() + } + // MARK: - UIWindowSceneDelegate func scene( @@ -148,11 +168,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe func sceneDidBecomeActive(_ scene: UIScene) { if isSceneConfigured { - accountDataThrottling.requestUpdate( - condition: settingsNavController == nil - ? .whenCloseToExpiryAndBeyond - : .always - ) + refreshDeviceAndAccountData(forceUpdate: false) } setShowsPrivacyOverlay(false) @@ -190,7 +206,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe let navController = makeSettingsNavigationController(route: route) // Refresh account data each time user opens settings - accountDataThrottling.requestUpdate(condition: .always) + refreshDeviceAndAccountData(forceUpdate: true) // On iPad the login controller can be presented modally above the root container. // in that case we have to use the presented controller to present the next modal. @@ -734,7 +750,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe ) { switch route { case .root, .account: - accountDataThrottling.requestUpdate(condition: .always) + refreshDeviceAndAccountData(forceUpdate: false) default: break @@ -903,10 +919,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, UISplitViewControllerDe } case .loggedOut: - accountDataThrottling.reset() + resetDeviceAndAccountDataThrottling() case .revoked: - accountDataThrottling.reset() + resetDeviceAndAccountDataThrottling() showRevokedDeviceView() } } diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift index 5dd4711ed1..c117dee394 100644 --- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift +++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift @@ -428,10 +428,7 @@ final class TunnelManager: StorePaymentObserver { operationQueue.addOperation(operation) } - func updateDeviceData(_ completionHandler: @escaping (OperationCompletion< - StoredDeviceData, - Error - >) -> Void) -> Cancellable { + func updateDeviceData(_ completionHandler: ((Error?) -> Void)? = nil) { let operation = UpdateDeviceDataOperation( dispatchQueue: internalQueue, interactor: TunnelInteractorProxy(self), @@ -442,11 +439,12 @@ final class TunnelManager: StorePaymentObserver { operation.completionHandler = { [weak self] completion in guard let self = self else { return } - if let error = completion.error { + let error = completion.error + if let error = error { self.checkIfDeviceRevoked(error) } - completionHandler(completion) + completionHandler?(error) } operation.addObserver( @@ -462,8 +460,6 @@ final class TunnelManager: StorePaymentObserver { ) operationQueue.addOperation(operation) - - return operation } func rotatePrivateKey( |
