summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-07-26 14:09:44 +0200
committerAndrej Mihajlov <and@mullvad.net>2022-07-28 11:28:37 +0200
commit695a95c5f55b17657f4f08d65da2e6368181a3d9 (patch)
tree1727dab4445ca79baa850990013666be0c8561c6
parent12a019fab64167417f5d1f40bd1e106c80d213c7 (diff)
downloadmullvadvpn-695a95c5f55b17657f4f08d65da2e6368181a3d9.tar.xz
mullvadvpn-695a95c5f55b17657f4f08d65da2e6368181a3d9.zip
AddressCache: drop error type
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj4
-rw-r--r--ios/MullvadVPN/AddressCache/AddressCacheStore.swift186
-rw-r--r--ios/MullvadVPN/AddressCache/AddressCacheStoreError.swift53
-rw-r--r--ios/MullvadVPN/AddressCache/AddressCacheTracker.swift41
4 files changed, 116 insertions, 168 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 75009f9de2..4922b11220 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -16,7 +16,6 @@
5807E2C02432038B00F5FF30 /* String+Split.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5807E2BF2432038B00F5FF30 /* String+Split.swift */; };
5807E2C2243203D000F5FF30 /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5807E2C1243203D000F5FF30 /* StringTests.swift */; };
5807E2C3243203E700F5FF30 /* String+Split.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5807E2BF2432038B00F5FF30 /* String+Split.swift */; };
- 58095C4B2760B4F200890776 /* AddressCacheStoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58095C4A2760B4F200890776 /* AddressCacheStoreError.swift */; };
58095C4F2760BA9100890776 /* AddressCacheStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58095C4E2760BA9100890776 /* AddressCacheStore.swift */; };
58095C512760BBB500890776 /* AddressCacheTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58095C502760BBB400890776 /* AddressCacheTracker.swift */; };
58095C532760EEC700890776 /* RESTNetworkOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58095C522760EEC700890776 /* RESTNetworkOperation.swift */; };
@@ -362,7 +361,6 @@
5808273928487E3E006B77A4 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
5808273B284888BC006B77A4 /* App.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = App.xcconfig; sourceTree = "<group>"; };
5808273C284888E5006B77A4 /* PacketTunnel.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = PacketTunnel.xcconfig; sourceTree = "<group>"; };
- 58095C4A2760B4F200890776 /* AddressCacheStoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCacheStoreError.swift; sourceTree = "<group>"; };
58095C4E2760BA9100890776 /* AddressCacheStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCacheStore.swift; sourceTree = "<group>"; };
58095C502760BBB400890776 /* AddressCacheTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCacheTracker.swift; sourceTree = "<group>"; };
58095C522760EEC700890776 /* RESTNetworkOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTNetworkOperation.swift; sourceTree = "<group>"; };
@@ -638,7 +636,6 @@
children = (
58FEAFB82750DA2F003C1625 /* AddressCache.swift */,
58095C4E2760BA9100890776 /* AddressCacheStore.swift */,
- 58095C4A2760B4F200890776 /* AddressCacheStoreError.swift */,
58095C502760BBB400890776 /* AddressCacheTracker.swift */,
);
path = AddressCache;
@@ -1383,7 +1380,6 @@
58F7CA882692E34000FC59FD /* WireguardKeysContentView.swift in Sources */,
58554F7B280B125F00013055 /* RESTAccountsProxy.swift in Sources */,
5801C9A527A14B2A0031566A /* TunnelManagerState.swift in Sources */,
- 58095C4B2760B4F200890776 /* AddressCacheStoreError.swift in Sources */,
5868585524054096000B8131 /* AppButton.swift in Sources */,
58781CC922AE7CA8009B9D8E /* RelayConstraints.swift in Sources */,
584E96BC240FD4DA00D3334F /* Location.swift in Sources */,
diff --git a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift b/ios/MullvadVPN/AddressCache/AddressCacheStore.swift
index 8ae790789e..2addeb2754 100644
--- a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift
+++ b/ios/MullvadVPN/AddressCache/AddressCacheStore.swift
@@ -41,6 +41,14 @@ extension AddressCache {
var source: CacheSource
}
+ struct EmptyCacheError: LocalizedError {
+ let source: CacheSource
+
+ var errorDescription: String? {
+ return "Address cache file from \(source) does not contain any API addresses."
+ }
+ }
+
class Store {
static let shared: Store = {
@@ -83,9 +91,46 @@ extension AddressCache {
init(cacheFileURL: URL, prebundledCacheFileURL: URL) {
self.cacheFileURL = cacheFileURL
self.prebundledCacheFileURL = prebundledCacheFileURL
- cachedAddresses = Self.defaultCachedAddresses
- initializeStore()
+ do {
+ let readResult = try Self.readFromCacheLocationWithFallback(
+ cacheFileURL: cacheFileURL,
+ prebundledCacheFileURL: prebundledCacheFileURL,
+ logger: logger
+ )
+
+ switch readResult.source {
+ case .disk:
+ cachedAddresses = readResult.cachedAddresses
+
+ case .bundle:
+ var addresses = readResult.cachedAddresses
+ addresses.endpoints.shuffle()
+ cachedAddresses = addresses
+
+ logger.debug("Persist address list read from bundle.")
+
+ do {
+ try writeToDisk()
+ } catch {
+ logger.error(
+ chainedError: AnyChainedError(error),
+ message: "Failed to persist address cache after reading it from bundle."
+ )
+ }
+ }
+
+ logger.debug(
+ """
+ Initialized cache from \(readResult.source) with \
+ \(cachedAddresses.endpoints.count) endpoint(s).
+ """
+ )
+ } catch {
+ logger.debug("Initialized cache with default API endpoint.")
+
+ cachedAddresses = Self.defaultCachedAddresses
+ }
}
func getCurrentEndpoint() -> AnyIPEndpoint {
@@ -123,12 +168,12 @@ extension AddressCache {
return currentEndpoint
}
- func setEndpoints(_ endpoints: [AnyIPEndpoint]) throws {
+ func setEndpoints(_ endpoints: [AnyIPEndpoint]) {
nslock.lock()
defer { nslock.unlock() }
guard !endpoints.isEmpty else {
- throw StoreError.emptyAddressList
+ return
}
if Set(cachedAddresses.endpoints) == Set(endpoints) {
@@ -150,7 +195,14 @@ extension AddressCache {
)
}
- try writeToDisk()
+ do {
+ try writeToDisk()
+ } catch {
+ logger.error(
+ chainedError: AnyChainedError(error),
+ message: "Failed to write address cache after setting new endpoints."
+ )
+ }
}
func getLastUpdateDate() -> Date {
@@ -160,85 +212,67 @@ extension AddressCache {
return cachedAddresses.updatedAt
}
- private func initializeStore() {
- let readResult: ReadResult
+ private static func readFromCacheLocationWithFallback(
+ cacheFileURL: URL,
+ prebundledCacheFileURL: URL,
+ logger: Logger
+ ) throws -> ReadResult
+ {
do {
- readResult = try readFromCacheLocationWithFallback()
+ let readResult = ReadResult(
+ cachedAddresses: try readFromCacheLocation(cacheFileURL),
+ source: .disk
+ )
+
+ try checkReadResultContainsEndpoints(readResult)
+
+ return readResult
} catch {
logger.error(
chainedError: AnyChainedError(error),
- message: "Failed to read address cache. Fallback to default API endpoint."
+ message: "Failed to read address cache from disk. Fallback to pre-bundled cache."
)
- cachedAddresses = Self.defaultCachedAddresses
-
- logger.debug("Initialized cache with default API endpoint.")
- return
- }
-
- guard !readResult.cachedAddresses.endpoints.isEmpty else {
- logger.debug("Read empty cache from \(readResult.source). Fallback to default API endpoint.")
-
- cachedAddresses = Self.defaultCachedAddresses
-
- logger.debug("Initialized cache with default API endpoint.")
-
- return
- }
-
- switch readResult.source {
- case .disk:
- cachedAddresses = readResult.cachedAddresses
-
- case .bundle:
- var addresses = readResult.cachedAddresses
- addresses.endpoints.shuffle()
- cachedAddresses = addresses
+ do {
+ let readResult = ReadResult(
+ cachedAddresses: try readFromBundle(prebundledCacheFileURL),
+ source: .bundle
+ )
- logger.debug("Persist address list read from bundle.")
+ try checkReadResultContainsEndpoints(readResult)
- do {
- try writeToDisk()
+ return readResult
} catch {
logger.error(
chainedError: AnyChainedError(error),
- message: "Failed to persist address cache after reading it from bundle."
+ message: "Failed to read address cache from bundle."
)
+
+ throw error
}
}
-
- logger.debug("Initialized cache from \(readResult.source) with \(cachedAddresses.endpoints.count) endpoint(s).")
}
- private func readFromCacheLocationWithFallback() throws -> ReadResult {
- do {
- return ReadResult(
- cachedAddresses: try readFromCacheLocation(),
- source: .disk
- )
- } catch {
- logger.error(
- chainedError: AnyChainedError(error),
- message: "Failed to read address cache from disk. Fallback to pre-bundled cache."
- )
+ private static func checkReadResultContainsEndpoints(_ readResult: ReadResult) throws {
+ if readResult.cachedAddresses.endpoints.isEmpty {
+ throw EmptyCacheError(source: readResult.source)
}
+ }
- return ReadResult(
- cachedAddresses: try readFromBundle(),
- source: .bundle
- )
+ private static func readFromCacheLocation(_ cacheFileURL: URL) throws -> CachedAddresses {
+ let data = try Data(contentsOf: cacheFileURL)
+
+ return try JSONDecoder().decode(CachedAddresses.self, from: data)
}
- private func readFromCacheLocation() throws -> CachedAddresses {
- do {
- let data = try Data(contentsOf: cacheFileURL)
+ private static func readFromBundle(_ prebundledCacheFileURL: URL) throws -> CachedAddresses {
+ let data = try Data(contentsOf: prebundledCacheFileURL)
+ let endpoints = try JSONDecoder().decode([AnyIPEndpoint].self, from: data)
- return try JSONDecoder().decode(CachedAddresses.self, from: data)
- } catch let error as DecodingError {
- throw StoreError.decodeCache(error)
- } catch {
- throw StoreError.readCache(error)
- }
+ return CachedAddresses(
+ updatedAt: Date(timeIntervalSince1970: 0),
+ endpoints: endpoints
+ )
}
private func writeToDisk() throws {
@@ -250,30 +284,8 @@ extension AddressCache {
attributes: nil
)
- do {
- let data = try JSONEncoder().encode(cachedAddresses)
- try data.write(to: cacheFileURL, options: .atomic)
- } catch let error as EncodingError {
- throw StoreError.encodeCache(error)
- } catch {
- throw StoreError.writeCache(error)
- }
- }
-
- private func readFromBundle() throws -> CachedAddresses {
- do {
- let data = try Data(contentsOf: prebundledCacheFileURL)
- let endpoints = try JSONDecoder().decode([AnyIPEndpoint].self, from: data)
-
- return CachedAddresses(
- updatedAt: Date(timeIntervalSince1970: 0),
- endpoints: endpoints
- )
- } catch let error as DecodingError {
- throw StoreError.decodeCacheFromBundle(error)
- } catch {
- throw StoreError.decodeCacheFromBundle(error)
- }
+ let data = try JSONEncoder().encode(cachedAddresses)
+ try data.write(to: cacheFileURL, options: .atomic)
}
}
diff --git a/ios/MullvadVPN/AddressCache/AddressCacheStoreError.swift b/ios/MullvadVPN/AddressCache/AddressCacheStoreError.swift
deleted file mode 100644
index 98fc8179e0..0000000000
--- a/ios/MullvadVPN/AddressCache/AddressCacheStoreError.swift
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// AddressCacheStoreError.swift
-// MullvadVPN
-//
-// Created by pronebird on 08/12/2021.
-// Copyright © 2021 Mullvad VPN AB. All rights reserved.
-//
-
-import Foundation
-
-extension AddressCache {
- enum StoreError: ChainedError {
- /// Failure to read address cache.
- case readCache(Swift.Error)
-
- /// Failure to read address cache from application bundle.
- case readCacheFromBundle(Swift.Error)
-
- /// Failure to write address cache.
- case writeCache(Swift.Error)
-
- /// Failure to decode address cache.
- case decodeCache(Swift.Error)
-
- /// Failure to encode address cache.
- case encodeCache(Swift.Error)
-
- /// Failure to decode address cache from application bundle.
- case decodeCacheFromBundle(Swift.Error)
-
- /// Failure to update endpoints with empty address list.
- case emptyAddressList
-
- var errorDescription: String? {
- switch self {
- case .readCache(_):
- return "Cannot read address cache"
- case .readCacheFromBundle(_):
- return "Cannot read address cache from application bundle"
- case .writeCache(_):
- return "Cannot write address cache"
- case .decodeCache(_):
- return "Cannot decode address cache"
- case .encodeCache(_):
- return "Cannot encode address cache"
- case .decodeCacheFromBundle(_):
- return "Cannot decode address cache from application bundle"
- case .emptyAddressList:
- return "Cannot update endpoints with empty address list"
- }
- }
- }
-}
diff --git a/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift b/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift
index 70397032ca..430212c24d 100644
--- a/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift
+++ b/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift
@@ -104,9 +104,12 @@ extension AddressCache {
}
let task = self.apiProxy.getAddressList(retryStrategy: .default) { completion in
- operation.finish(
- completion: self.handleResponse(completion: completion)
- )
+ self.setEndpoints(from: completion)
+
+ let mappedCompletion = completion.map { _ in true }
+ .eraseFailureType()
+
+ operation.finish(completion: mappedCompletion)
}
operation.addCancellationBlock {
@@ -133,36 +136,26 @@ extension AddressCache {
return _nextScheduleDate()
}
- private func handleResponse(
- completion: OperationCompletion<[AnyIPEndpoint], REST.Error>
- ) -> OperationCompletion<Bool, Error>
+ private func setEndpoints(from completion: OperationCompletion<[AnyIPEndpoint], REST.Error>)
{
- let mappedCompletion = completion
- .flatMapError { error -> OperationCompletion<[AnyIPEndpoint], REST.Error> in
- if case URLError.cancelled = error {
- return .cancelled
- } else {
- return .failure(error)
- }
- }
- .tryMap { endpoints -> Bool in
- try store.setEndpoints(endpoints)
-
- return true
- }
-
nslock.lock()
- lastFailureAttemptDate = mappedCompletion.isSuccess ? nil : Date()
- nslock.unlock()
+ defer { nslock.unlock() }
- if let error = mappedCompletion.error {
+ switch completion {
+ case .success(let endpoints):
+ store.setEndpoints(endpoints)
+
+ case .failure(let error):
logger.error(
chainedError: AnyChainedError(error),
message: "Failed to update address cache."
)
+
+ case .cancelled:
+ break
}
- return mappedCompletion
+ lastFailureAttemptDate = completion.isSuccess ? nil : Date()
}
private func scheduleEndpointsUpdate(startTime: DispatchWallTime) {