diff options
| author | sajacl <sajaclvishkai@gmail.com> | 2022-10-21 13:27:05 +0200 |
|---|---|---|
| committer | sajacl <sajaclvishkai@gmail.com> | 2022-10-21 15:16:32 +0200 |
| commit | 8ad5803493f26eefaa4d2e72980919e3b7233cd7 (patch) | |
| tree | f543cabaa48d6e942b79500d0129d9606484f713 /ios/RelayCache | |
| parent | d3ef8d298dbd3ceee5bc2dfbe0c25d610e664c5f (diff) | |
| download | mullvadvpn-8ad5803493f26eefaa4d2e72980919e3b7233cd7.tar.xz mullvadvpn-8ad5803493f26eefaa4d2e72980919e3b7233cd7.zip | |
Move RelayCache.IO and CachedRelays into new RelayCache.framework
Moved RelayCache.IO and CachedRelays into new RelayCache.framework
Moved prebuild script to build phase script.
Renamed script, renamed/moved RelayCache.IO to RelayCache.
Renamed RelayCache.Tracker to RelayCacheTracker.
Set APPLICATION_EXTENSION_API_ONLY to true for RelayCache framework.
Updated gitignore.
Removed relays.json from git.
Removed relays.json from RelayCache framework
Removed RelayCache/FetchResult, moved/renamed code into RelayCacheTracker file.
Renamed CachedRelaysFetchResult to RelaysFetchResult.
Changed access level for RelaysFetchResult and NoCachedRelaysError.
Diffstat (limited to 'ios/RelayCache')
| -rw-r--r-- | ios/RelayCache/CachedRelays.swift | 28 | ||||
| -rw-r--r-- | ios/RelayCache/RelayCache.h | 19 | ||||
| -rw-r--r-- | ios/RelayCache/RelayCache.swift | 110 |
3 files changed, 157 insertions, 0 deletions
diff --git a/ios/RelayCache/CachedRelays.swift b/ios/RelayCache/CachedRelays.swift new file mode 100644 index 0000000000..6ff9c36091 --- /dev/null +++ b/ios/RelayCache/CachedRelays.swift @@ -0,0 +1,28 @@ +// +// CachedRelays.swift +// CachedRelays +// +// Created by pronebird on 27/07/2021. +// Copyright © 2021 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadREST + +/// A struct that represents the relay cache on disk +public struct CachedRelays: Codable { + /// E-tag returned by server + public var etag: String? + + /// The relay list stored within the cache entry + public var relays: REST.ServerRelaysResponse + + /// The date when this cache was last updated + public var updatedAt: Date + + public init(etag: String? = nil, relays: REST.ServerRelaysResponse, updatedAt: Date) { + self.etag = etag + self.relays = relays + self.updatedAt = updatedAt + } +} diff --git a/ios/RelayCache/RelayCache.h b/ios/RelayCache/RelayCache.h new file mode 100644 index 0000000000..abe3d1b983 --- /dev/null +++ b/ios/RelayCache/RelayCache.h @@ -0,0 +1,19 @@ +// +// RelayCache.h +// RelayCache +// +// Created by Sajad Vishkai on 2022-10-21. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +#import <Foundation/Foundation.h> + +//! Project version number for RelayCache. +FOUNDATION_EXPORT double RelayCacheVersionNumber; + +//! Project version string for RelayCache. +FOUNDATION_EXPORT const unsigned char RelayCacheVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import <RelayCache/PublicHeader.h> + + diff --git a/ios/RelayCache/RelayCache.swift b/ios/RelayCache/RelayCache.swift new file mode 100644 index 0000000000..64ce748128 --- /dev/null +++ b/ios/RelayCache/RelayCache.swift @@ -0,0 +1,110 @@ +// +// RelayCache.swift +// RelayCache +// +// Created by pronebird on 06/09/2021. +// Copyright © 2021 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadREST + +public class RelayCache { + /// The default cache file location bound by app group container. + public static func defaultCacheFileURL( + forSecurityApplicationGroupIdentifier appGroupIdentifier: String + ) -> URL? { + let containerURL = FileManager.default.containerURL( + forSecurityApplicationGroupIdentifier: appGroupIdentifier + ) + + return containerURL?.appendingPathComponent("relays.json") + } + + /// The path to pre-bundled `relays.json` file. + public static var preBundledRelaysFileURL: URL? { + return Bundle(for: Self.self).url(forResource: "relays", withExtension: "json") + } + + /// Safely read the cache file from disk using file coordinator. + public static func read(cacheFileURL: URL) throws -> CachedRelays { + var result: Result<CachedRelays, Error>? + let fileCoordinator = NSFileCoordinator(filePresenter: nil) + + let accessor = { (fileURLForReading: URL) in + result = Result { + let data = try Data(contentsOf: fileURLForReading) + return try JSONDecoder().decode(CachedRelays.self, from: data) + } + } + + var error: NSError? + fileCoordinator.coordinate( + readingItemAt: cacheFileURL, + options: [.withoutChanges], + error: &error, + byAccessor: accessor + ) + + if let error = error { + result = .failure(error) + } + + return try result!.get() + } + + /// Safely read the cache file from disk using file coordinator and fallback to prebundled + /// relays in case if the relay cache file is missing. + public static func readWithFallback(cacheFileURL: URL, preBundledRelaysFileURL: URL) + throws -> CachedRelays + { + do { + return try Self.read(cacheFileURL: cacheFileURL) + } catch { + if error is DecodingError || (error as? CocoaError)?.code == .fileReadNoSuchFile { + return try Self.readPrebundledRelays(fileURL: preBundledRelaysFileURL) + } else { + throw error + } + } + } + + /// Read pre-bundled relays file from disk. + public static func readPrebundledRelays(fileURL: URL) throws -> CachedRelays { + let data = try Data(contentsOf: fileURL) + let relays = try REST.Coding.makeJSONDecoder() + .decode(REST.ServerRelaysResponse.self, from: data) + + return CachedRelays( + relays: relays, + updatedAt: Date(timeIntervalSince1970: 0) + ) + } + + /// Safely write the cache file on disk using file coordinator. + public static func write(cacheFileURL: URL, record: CachedRelays) throws { + var result: Result<Void, Error>? + let fileCoordinator = NSFileCoordinator(filePresenter: nil) + + let accessor = { (fileURLForWriting: URL) in + result = Result { + let data = try JSONEncoder().encode(record) + try data.write(to: fileURLForWriting) + } + } + + var error: NSError? + fileCoordinator.coordinate( + writingItemAt: cacheFileURL, + options: [.forReplacing], + error: &error, + byAccessor: accessor + ) + + if let error = error { + result = .failure(error) + } + + try result?.get() + } +} |
