summaryrefslogtreecommitdiffhomepage
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
parent8c2d907f30b68abda7833072ff1204bd84289225 (diff)
downloadmullvadvpn-d1615c02f4c2f55235bb41dceaa9c1085590658f.tar.xz
mullvadvpn-d1615c02f4c2f55235bb41dceaa9c1085590658f.zip
Remove dangling files that were previous removed
-rw-r--r--ios/MullvadVPN/AddressCache/AddressCache.swift11
-rw-r--r--ios/MullvadVPN/AddressCache/AddressCacheStore.swift302
-rw-r--r--ios/MullvadVPN/AddressCache/AddressCacheTracker.swift201
3 files changed, 0 insertions, 514 deletions
diff --git a/ios/MullvadVPN/AddressCache/AddressCache.swift b/ios/MullvadVPN/AddressCache/AddressCache.swift
deleted file mode 100644
index 77fb8fc5c4..0000000000
--- a/ios/MullvadVPN/AddressCache/AddressCache.swift
+++ /dev/null
@@ -1,11 +0,0 @@
-//
-// AddressCache.swift
-// MullvadVPN
-//
-// Created by pronebird on 26/11/2021.
-// Copyright © 2021 Mullvad VPN AB. All rights reserved.
-//
-
-import Foundation
-
-enum AddressCache {}
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)
- }
- }
-}
diff --git a/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift b/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift
deleted file mode 100644
index 56b92d06e3..0000000000
--- a/ios/MullvadVPN/AddressCache/AddressCacheTracker.swift
+++ /dev/null
@@ -1,201 +0,0 @@
-//
-// AddressCacheTracker.swift
-// MullvadVPN
-//
-// Created by pronebird on 08/12/2021.
-// Copyright © 2021 Mullvad VPN AB. All rights reserved.
-//
-
-import MullvadLogging
-import Operations
-import UIKit
-
-extension AddressCache {
- class Tracker {
- /// Shared instance.
- static let shared = AddressCache.Tracker(
- apiProxy: REST.ProxyFactory.shared.createAPIProxy(),
- store: AddressCache.Store.shared
- )
-
- /// Update interval (in seconds).
- private static let updateInterval: TimeInterval = 60 * 60 * 24
-
- /// Retry interval (in seconds).
- private static let retryInterval: TimeInterval = 60 * 15
-
- /// Logger.
- private let logger = Logger(label: "AddressCache.Tracker")
-
- /// REST API proxy.
- private let apiProxy: REST.APIProxy
-
- /// Store.
- private let store: AddressCache.Store
-
- /// A flag that indicates whether periodic updates are running
- private var isPeriodicUpdatesEnabled = false
-
- /// The date of last failed attempt.
- private var lastFailureAttemptDate: Date?
-
- /// Timer used for scheduling periodic updates.
- private var timer: DispatchSourceTimer?
-
- /// Operation queue.
- private let operationQueue: AsyncOperationQueue = {
- let operationQueue = AsyncOperationQueue()
- operationQueue.maxConcurrentOperationCount = 1
- return operationQueue
- }()
-
- /// Lock used for synchronizing member access.
- private let nslock = NSLock()
-
- /// Designated initializer
- private init(apiProxy: REST.APIProxy, store: AddressCache.Store) {
- self.apiProxy = apiProxy
- self.store = store
- }
-
- func startPeriodicUpdates() {
- nslock.lock()
- defer { nslock.unlock() }
-
- guard !isPeriodicUpdatesEnabled else {
- return
- }
-
- logger.debug("Start periodic address cache updates.")
-
- isPeriodicUpdatesEnabled = true
-
- let scheduleDate = _nextScheduleDate()
-
- logger.debug("Schedule address cache update at \(scheduleDate.logFormatDate()).")
-
- scheduleEndpointsUpdate(startTime: .now() + scheduleDate.timeIntervalSinceNow)
- }
-
- func stopPeriodicUpdates() {
- nslock.lock()
- defer { nslock.unlock() }
-
- guard isPeriodicUpdatesEnabled else { return }
-
- logger.debug("Stop periodic address cache updates.")
-
- isPeriodicUpdatesEnabled = false
-
- timer?.cancel()
- timer = nil
- }
-
- func updateEndpoints(
- completionHandler: ((OperationCompletion<Bool, Error>) -> Void)? = nil
- ) -> Cancellable {
- let operation = ResultBlockOperation<Bool, Error> { operation in
- guard self.nextScheduleDate() <= Date() else {
- operation.finish(completion: .success(false))
- return
- }
-
- let task = self.apiProxy.getAddressList(retryStrategy: .default) { completion in
- self.setEndpoints(from: completion)
-
- let mappedCompletion = completion.map { _ in true }
- .eraseFailureType()
-
- operation.finish(completion: mappedCompletion)
- }
-
- operation.addCancellationBlock {
- task.cancel()
- }
- }
-
- operation.completionQueue = .main
- operation.completionHandler = completionHandler
-
- operation.addObserver(
- BackgroundObserver(name: "Update endpoints", cancelUponExpiration: true)
- )
-
- operationQueue.addOperation(operation)
-
- return operation
- }
-
- func nextScheduleDate() -> Date {
- nslock.lock()
- defer { nslock.unlock() }
-
- return _nextScheduleDate()
- }
-
- private func setEndpoints(from completion: OperationCompletion<[AnyIPEndpoint], REST.Error>)
- {
- nslock.lock()
- defer { nslock.unlock() }
-
- switch completion {
- case let .success(endpoints):
- store.setEndpoints(endpoints)
-
- case let .failure(error):
- logger.error(
- error: error,
- message: "Failed to update address cache."
- )
-
- case .cancelled:
- break
- }
-
- lastFailureAttemptDate = completion.isSuccess ? nil : Date()
- }
-
- private func scheduleEndpointsUpdate(startTime: DispatchWallTime) {
- let newTimer = DispatchSource.makeTimerSource()
- newTimer.setEventHandler { [weak self] in
- self?.handleTimer()
- }
-
- newTimer.schedule(wallDeadline: startTime)
- newTimer.activate()
-
- timer?.cancel()
- timer = newTimer
- }
-
- private func handleTimer() {
- _ = updateEndpoints { _ in
- self.nslock.lock()
- defer { self.nslock.unlock() }
-
- guard self.isPeriodicUpdatesEnabled else { return }
-
- let scheduleDate = self._nextScheduleDate()
-
- self.logger
- .debug("Schedule next address cache update at \(scheduleDate.logFormatDate()).")
-
- self.scheduleEndpointsUpdate(startTime: .now() + scheduleDate.timeIntervalSinceNow)
- }
- }
-
- private func _nextScheduleDate() -> Date {
- let nextDate = lastFailureAttemptDate.map { date in
- return Date(
- timeInterval: Self.retryInterval,
- since: date
- )
- } ?? Date(
- timeInterval: Self.updateInterval,
- since: store.getLastUpdateDate()
- )
-
- return max(nextDate, Date())
- }
- }
-}