diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2023-03-02 12:55:17 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2023-03-02 12:55:17 +0100 |
| commit | d1615c02f4c2f55235bb41dceaa9c1085590658f (patch) | |
| tree | 92eaca688aa91707236a083be77ef803f691cd60 /ios/MullvadVPN/AddressCache/AddressCacheStore.swift | |
| parent | 8c2d907f30b68abda7833072ff1204bd84289225 (diff) | |
| download | mullvadvpn-d1615c02f4c2f55235bb41dceaa9c1085590658f.tar.xz mullvadvpn-d1615c02f4c2f55235bb41dceaa9c1085590658f.zip | |
Remove dangling files that were previous removed
Diffstat (limited to 'ios/MullvadVPN/AddressCache/AddressCacheStore.swift')
| -rw-r--r-- | ios/MullvadVPN/AddressCache/AddressCacheStore.swift | 302 |
1 files changed, 0 insertions, 302 deletions
diff --git a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift b/ios/MullvadVPN/AddressCache/AddressCacheStore.swift deleted file mode 100644 index aed04fd59b..0000000000 --- a/ios/MullvadVPN/AddressCache/AddressCacheStore.swift +++ /dev/null @@ -1,302 +0,0 @@ -// -// AddressCacheStore.swift -// MullvadVPN -// -// Created by pronebird on 08/12/2021. -// Copyright © 2021 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import MullvadLogging - -extension AddressCache { - struct CachedAddresses: Codable { - /// Date when the cached addresses were last updated. - var updatedAt: Date - - /// API endpoints. - var endpoints: [AnyIPEndpoint] - } - - enum CacheSource: CustomStringConvertible { - /// Cache file originates from disk location. - case disk - - /// Cache file originates from application bundle. - case bundle - - var description: String { - switch self { - case .disk: - return "disk" - case .bundle: - return "bundle" - } - } - } - - struct ReadResult { - var cachedAddresses: CachedAddresses - 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 = { - let cacheFilename = "api-ip-address.json" - let cacheDirectoryURL = FileManager.default.urls( - for: .applicationSupportDirectory, - in: .userDomainMask - ).first! - let cacheFileURL = cacheDirectoryURL.appendingPathComponent( - cacheFilename, - isDirectory: false - ) - let prebundledCacheFileURL = Bundle.main.url( - forResource: cacheFilename, - withExtension: nil - )! - - return Store( - cacheFileURL: cacheFileURL, - prebundledCacheFileURL: prebundledCacheFileURL - ) - }() - - static var defaultCachedAddresses: CachedAddresses { - return CachedAddresses( - updatedAt: Date(timeIntervalSince1970: 0), - endpoints: [ - ApplicationConfiguration.defaultAPIEndpoint, - ] - ) - } - - /// Logger. - private let logger = Logger(label: "AddressCache.Store") - - /// Memory cache. - private var cachedAddresses: CachedAddresses - - /// Cache file location. - private let cacheFileURL: URL - - /// The location of pre-bundled address cache file. - private let prebundledCacheFileURL: URL - - /// Lock used for synchronizing access to instance members. - private let nslock = NSLock() - - /// Designated initializer - init(cacheFileURL: URL, prebundledCacheFileURL: URL) { - self.cacheFileURL = cacheFileURL - self.prebundledCacheFileURL = prebundledCacheFileURL - - 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( - error: 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 { - nslock.lock() - defer { nslock.unlock() } - return cachedAddresses.endpoints.first! - } - - func selectNextEndpoint(_ failedEndpoint: AnyIPEndpoint) -> AnyIPEndpoint { - nslock.lock() - defer { nslock.unlock() } - - var currentEndpoint = cachedAddresses.endpoints.first! - - guard failedEndpoint == currentEndpoint else { - return currentEndpoint - } - - cachedAddresses.endpoints.removeFirst() - cachedAddresses.endpoints.append(failedEndpoint) - - currentEndpoint = cachedAddresses.endpoints.first! - - logger - .debug( - "Failed to communicate using \(failedEndpoint). Next endpoint: \(currentEndpoint)" - ) - - do { - try writeToDisk() - } catch { - logger.error( - error: error, - message: "Failed to write address cache after selecting next endpoint." - ) - } - - return currentEndpoint - } - - func setEndpoints(_ endpoints: [AnyIPEndpoint]) { - nslock.lock() - defer { nslock.unlock() } - - guard !endpoints.isEmpty else { - return - } - - if Set(cachedAddresses.endpoints) == Set(endpoints) { - cachedAddresses.updatedAt = Date() - } else { - // Shuffle new endpoints - var newEndpoints = endpoints.shuffled() - - // Move current endpoint to the top of the list - let currentEndpoint = cachedAddresses.endpoints.first! - if let index = newEndpoints.firstIndex(of: currentEndpoint) { - newEndpoints.remove(at: index) - newEndpoints.insert(currentEndpoint, at: 0) - } - - cachedAddresses = CachedAddresses( - updatedAt: Date(), - endpoints: newEndpoints - ) - } - - do { - try writeToDisk() - } catch { - logger.error( - error: error, - message: "Failed to write address cache after setting new endpoints." - ) - } - } - - func getLastUpdateDate() -> Date { - nslock.lock() - defer { nslock.unlock() } - - return cachedAddresses.updatedAt - } - - private static func readFromCacheLocationWithFallback( - cacheFileURL: URL, - prebundledCacheFileURL: URL, - logger: Logger - ) throws -> ReadResult { - do { - let readResult = ReadResult( - cachedAddresses: try readFromCacheLocation(cacheFileURL), - source: .disk - ) - - try checkReadResultContainsEndpoints(readResult) - - return readResult - } catch { - logger.error( - error: error, - message: "Failed to read address cache from disk. Fallback to pre-bundled cache." - ) - - do { - let readResult = ReadResult( - cachedAddresses: try readFromBundle(prebundledCacheFileURL), - source: .bundle - ) - - try checkReadResultContainsEndpoints(readResult) - - return readResult - } catch { - logger.error( - error: error, - message: "Failed to read address cache from bundle." - ) - - throw error - } - } - } - - private static func checkReadResultContainsEndpoints(_ readResult: ReadResult) throws { - if readResult.cachedAddresses.endpoints.isEmpty { - throw EmptyCacheError(source: readResult.source) - } - } - - private static func readFromCacheLocation(_ cacheFileURL: URL) throws -> CachedAddresses { - let data = try Data(contentsOf: cacheFileURL) - - return try JSONDecoder().decode(CachedAddresses.self, from: data) - } - - private static func readFromBundle(_ prebundledCacheFileURL: URL) throws - -> CachedAddresses - { - let data = try Data(contentsOf: prebundledCacheFileURL) - let endpoints = try JSONDecoder().decode([AnyIPEndpoint].self, from: data) - - return CachedAddresses( - updatedAt: Date(timeIntervalSince1970: 0), - endpoints: endpoints - ) - } - - private func writeToDisk() throws { - let cacheDirectoryURL = cacheFileURL.deletingLastPathComponent() - - try? FileManager.default.createDirectory( - at: cacheDirectoryURL, - withIntermediateDirectories: true, - attributes: nil - ) - - let data = try JSONEncoder().encode(cachedAddresses) - try data.write(to: cacheFileURL, options: .atomic) - } - } -} |
