summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/AddressCache/AddressCacheStore.swift
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2023-03-02 12:55:17 +0100
committerAndrej Mihajlov <and@mullvad.net>2023-03-02 12:55:17 +0100
commitd1615c02f4c2f55235bb41dceaa9c1085590658f (patch)
tree92eaca688aa91707236a083be77ef803f691cd60 /ios/MullvadVPN/AddressCache/AddressCacheStore.swift
parent8c2d907f30b68abda7833072ff1204bd84289225 (diff)
downloadmullvadvpn-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.swift302
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)
- }
- }
-}