summaryrefslogtreecommitdiffhomepage
path: root/ios
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-12-13 10:19:43 +0100
committerAndrej Mihajlov <and@mullvad.net>2022-12-13 14:42:27 +0100
commit00a0ec2adcfdd7c15c25f0a1bfeb9554d85ba17a (patch)
tree30e0b33ed4b47c6d040e9a006da984a1fb663dd4 /ios
parent800c01bf3d521f23b919e7d5bb0c0a2cf386ec01 (diff)
downloadmullvadvpn-00a0ec2adcfdd7c15c25f0a1bfeb9554d85ba17a.tar.xz
mullvadvpn-00a0ec2adcfdd7c15c25f0a1bfeb9554d85ba17a.zip
Periodically update device data while capping it at 1 update per minute
Diffstat (limited to 'ios')
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj4
-rw-r--r--ios/MullvadVPN/AccountDataThrottling.swift2
-rw-r--r--ios/MullvadVPN/DeviceDataThrottling.swift55
-rw-r--r--ios/MullvadVPN/SceneDelegate.swift38
-rw-r--r--ios/MullvadVPN/TunnelManager/TunnelManager.swift12
5 files changed, 91 insertions, 20 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index a4aba1db17..f37fd833ba 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -85,6 +85,7 @@
580F8B8628197958002E0998 /* DNSSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 580F8B8528197958002E0998 /* DNSSettings.swift */; };
580F8B872819795C002E0998 /* DNSSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 580F8B8528197958002E0998 /* DNSSettings.swift */; };
5811DE50239014550011EB53 /* NEVPNStatus+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */; };
+ 58138E61294871C600684F0C /* DeviceDataThrottling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58138E60294871C600684F0C /* DeviceDataThrottling.swift */; };
5818139F28E09BD8002817DE /* libOperations.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58E5126528DDF04200B0BCDE /* libOperations.a */; };
581813A128E09DBB002817DE /* NoCancelledDependenciesCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581813A028E09DBB002817DE /* NoCancelledDependenciesCondition.swift */; };
581813A328E09DCD002817DE /* NoFailedDependenciesCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581813A228E09DCD002817DE /* NoFailedDependenciesCondition.swift */; };
@@ -598,6 +599,7 @@
580F8B8228197881002E0998 /* TunnelSettingsV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV2.swift; sourceTree = "<group>"; };
580F8B8528197958002E0998 /* DNSSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSSettings.swift; sourceTree = "<group>"; };
5811DE4F239014550011EB53 /* NEVPNStatus+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEVPNStatus+Debug.swift"; sourceTree = "<group>"; };
+ 58138E60294871C600684F0C /* DeviceDataThrottling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceDataThrottling.swift; sourceTree = "<group>"; };
581813A028E09DBB002817DE /* NoCancelledDependenciesCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCancelledDependenciesCondition.swift; sourceTree = "<group>"; };
581813A228E09DCD002817DE /* NoFailedDependenciesCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoFailedDependenciesCondition.swift; sourceTree = "<group>"; };
581813A428E09DE2002817DE /* BlockCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockCondition.swift; sourceTree = "<group>"; };
@@ -1327,6 +1329,7 @@
06AC114028F841390037AF9A /* AddressCacheTracker.swift */,
5896CEF126972DEB00B0FAE8 /* AccountContentView.swift */,
587988C628A2A01F00E3DF54 /* AccountDataThrottling.swift */,
+ 58138E60294871C600684F0C /* DeviceDataThrottling.swift */,
58C3A4B122456F1A00340BDB /* AccountInputGroupView.swift */,
58CCA01D2242787B004F3011 /* AccountTextField.swift */,
582AE30F2440A6CA00E6733A /* AccountTokenInput.swift */,
@@ -2250,6 +2253,7 @@
58F2E146276A2C9900A79513 /* StopTunnelOperation.swift in Sources */,
E1187ABC289BBB850024E748 /* OutOfTimeViewController.swift in Sources */,
58293FB125124117005D0BB5 /* CustomTextField.swift in Sources */,
+ 58138E61294871C600684F0C /* DeviceDataThrottling.swift in Sources */,
5878A279290954790096FC88 /* ConnectInteractor.swift in Sources */,
582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */,
5820EDAB288FF0D2006BF4E4 /* DeviceRowView.swift in Sources */,
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(