summaryrefslogtreecommitdiffhomepage
path: root/ios/RelayCache
diff options
context:
space:
mode:
authorsajacl <sajaclvishkai@gmail.com>2022-10-21 13:27:05 +0200
committersajacl <sajaclvishkai@gmail.com>2022-10-21 15:16:32 +0200
commit8ad5803493f26eefaa4d2e72980919e3b7233cd7 (patch)
treef543cabaa48d6e942b79500d0129d9606484f713 /ios/RelayCache
parentd3ef8d298dbd3ceee5bc2dfbe0c25d610e664c5f (diff)
downloadmullvadvpn-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.swift28
-rw-r--r--ios/RelayCache/RelayCache.h19
-rw-r--r--ios/RelayCache/RelayCache.swift110
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()
+ }
+}