diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-05-17 17:21:06 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-05-18 10:13:34 +0200 |
| commit | 128cf756bb365e0255c37cc2f18c018654a886ae (patch) | |
| tree | 8fa67639d7a8117510a36d73979b0805dd81986a | |
| parent | 31dd0e0e24b9785c975107e872624168c13b98e9 (diff) | |
| download | mullvadvpn-128cf756bb365e0255c37cc2f18c018654a886ae.tar.xz mullvadvpn-128cf756bb365e0255c37cc2f18c018654a886ae.zip | |
AddressCacheStore: throw error instead of returning result
| -rw-r--r-- | ios/MullvadVPN/AddressCache/AddressCacheStore.swift | 196 |
1 files changed, 104 insertions, 92 deletions
diff --git a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift b/ios/MullvadVPN/AddressCache/AddressCacheStore.swift index 745e83dc9d..8ae790789e 100644 --- a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift +++ b/ios/MullvadVPN/AddressCache/AddressCacheStore.swift @@ -100,28 +100,35 @@ extension AddressCache { var currentEndpoint = cachedAddresses.endpoints.first! - if failedEndpoint == currentEndpoint { - cachedAddresses.endpoints.removeFirst() - cachedAddresses.endpoints.append(failedEndpoint) + guard failedEndpoint == currentEndpoint else { + return currentEndpoint + } - currentEndpoint = cachedAddresses.endpoints.first! + cachedAddresses.endpoints.removeFirst() + cachedAddresses.endpoints.append(failedEndpoint) - logger.debug("Failed to communicate using \(failedEndpoint). Next endpoint: \(currentEndpoint)") + currentEndpoint = cachedAddresses.endpoints.first! - if case .failure(let error) = writeToDisk() { - logger.error(chainedError: error, message: "Failed to write address cache after selecting next endpoint.") - } + logger.debug("Failed to communicate using \(failedEndpoint). Next endpoint: \(currentEndpoint)") + + do { + try writeToDisk() + } catch { + logger.error( + chainedError: AnyChainedError(error), + message: "Failed to write address cache after selecting next endpoint." + ) } return currentEndpoint } - func setEndpoints(_ endpoints: [AnyIPEndpoint]) -> Result<Void, AddressCache.StoreError> { + func setEndpoints(_ endpoints: [AnyIPEndpoint]) throws { nslock.lock() defer { nslock.unlock() } guard !endpoints.isEmpty else { - return .failure(.emptyAddressList) + throw StoreError.emptyAddressList } if Set(cachedAddresses.endpoints) == Set(endpoints) { @@ -143,7 +150,7 @@ extension AddressCache { ) } - return writeToDisk() + try writeToDisk() } func getLastUpdateDate() -> Date { @@ -154,77 +161,87 @@ extension AddressCache { } private func initializeStore() { - switch readFromCacheLocationWithFallback() { - case .success(let readResult): - if readResult.cachedAddresses.endpoints.isEmpty { - logger.debug("Read empty cache from \(readResult.source). Fallback to default API endpoint.") + let readResult: ReadResult + do { + readResult = try readFromCacheLocationWithFallback() + } catch { + logger.error( + chainedError: AnyChainedError(error), + message: "Failed to read address cache. Fallback to default API endpoint." + ) - cachedAddresses = Self.defaultCachedAddresses + cachedAddresses = Self.defaultCachedAddresses - logger.debug("Initialized cache with default API endpoint.") - } else { - switch readResult.source { - case .disk: - cachedAddresses = readResult.cachedAddresses + logger.debug("Initialized cache with default API endpoint.") + return + } - case .bundle: - var addresses = readResult.cachedAddresses - addresses.endpoints.shuffle() - cachedAddresses = addresses + guard !readResult.cachedAddresses.endpoints.isEmpty else { + logger.debug("Read empty cache from \(readResult.source). Fallback to default API endpoint.") - logger.debug("Persist address list read from bundle.") + cachedAddresses = Self.defaultCachedAddresses - if case .failure(let error) = writeToDisk() { - logger.error(chainedError: error, message: "Failed to persist address cache after reading it from bundle.") - } - } + logger.debug("Initialized cache with default API endpoint.") - logger.debug("Initialized cache from \(readResult.source) with \(cachedAddresses.endpoints.count) endpoint(s).") - } + return + } - case .failure(let error): - logger.error(chainedError: error, message: "Failed to read address cache. Fallback to default API endpoint.") + switch readResult.source { + case .disk: + cachedAddresses = readResult.cachedAddresses - cachedAddresses = Self.defaultCachedAddresses + case .bundle: + var addresses = readResult.cachedAddresses + addresses.endpoints.shuffle() + cachedAddresses = addresses - logger.debug("Initialized cache with default API endpoint.") - } - } + logger.debug("Persist address list read from bundle.") - private func readFromCacheLocationWithFallback() -> Result<ReadResult, AddressCache.StoreError> { - return readFromCacheLocation() - .map { addresses in - return ReadResult( - cachedAddresses: addresses, - source: .disk + do { + try writeToDisk() + } catch { + logger.error( + chainedError: AnyChainedError(error), + message: "Failed to persist address cache after reading it from bundle." ) } - .flatMapError { error in - logger.error(chainedError: error, message: "Failed to read address cache from disk. Fallback to pre-bundled cache.") + } - return readFromBundle().map { cachedAddresses in - return ReadResult( - cachedAddresses: cachedAddresses, - source: .bundle - ) - } - } + logger.debug("Initialized cache from \(readResult.source) with \(cachedAddresses.endpoints.count) endpoint(s).") } - private func readFromCacheLocation() -> Result<CachedAddresses, AddressCache.StoreError> { - return Result { try Data(contentsOf: cacheFileURL) } - .mapError { error in - return .readCache(error) - } - .flatMap { data in - return Result { try JSONDecoder().decode(CachedAddresses.self, from: data) } - .mapError { error in - return .decodeCache(error) - } - } + 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." + ) + } + + return ReadResult( + cachedAddresses: try readFromBundle(), + source: .bundle + ) } - private func writeToDisk() -> Result<(), AddressCache.StoreError> { + private func readFromCacheLocation() throws -> CachedAddresses { + do { + let data = try Data(contentsOf: cacheFileURL) + + return try JSONDecoder().decode(CachedAddresses.self, from: data) + } catch let error as DecodingError { + throw StoreError.decodeCache(error) + } catch { + throw StoreError.readCache(error) + } + } + + private func writeToDisk() throws { let cacheDirectoryURL = cacheFileURL.deletingLastPathComponent() try? FileManager.default.createDirectory( @@ -233,35 +250,30 @@ extension AddressCache { attributes: nil ) - return Result { try JSONEncoder().encode(cachedAddresses) } - .mapError { error in - return .encodeCache(error) - } - .flatMap { data in - return Result { try data.write(to: cacheFileURL, options: .atomic) } - .mapError { error in - return .writeCache(error) - } - } + 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() -> Result<CachedAddresses, AddressCache.StoreError> { - return Result { try Data(contentsOf: prebundledCacheFileURL) } - .mapError { error in - return .readCacheFromBundle(error) - } - .flatMap { data in - return Result { try JSONDecoder().decode([AnyIPEndpoint].self, from: data) } - .mapError { error in - return .decodeCacheFromBundle(error) - } - .map { endpoints in - return CachedAddresses( - updatedAt: Date(timeIntervalSince1970: 0), - endpoints: endpoints - ) - } - } + 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) + } } } |
