-
Notifications
You must be signed in to change notification settings - Fork 384
/
Copy pathRelayCache.swift
64 lines (54 loc) · 2.13 KB
/
RelayCache.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//
// RelayCache.swift
// RelayCache
//
// Created by pronebird on 06/09/2021.
// Copyright © 2021 Mullvad VPN AB. All rights reserved.
//
import Foundation
import MullvadTypes
public protocol RelayCacheProtocol {
func read() throws -> CachedRelays
func write(record: CachedRelays) throws
}
/// - Warning: `RelayCache` should not be used directly. It should be used through `IPOverrideWrapper` to have
/// ip overrides applied.
public final class RelayCache: RelayCacheProtocol {
private let fileCache: any FileCacheProtocol<CachedRelays>
/// Designated initializer
public init(cacheDirectory: URL) {
fileCache = FileCache(fileURL: cacheDirectory.appendingPathComponent("relays.json", isDirectory: false))
}
/// Initializer that accepts a custom FileCache implementation. Used in tests.
init(fileCache: some FileCacheProtocol<CachedRelays>) {
self.fileCache = fileCache
}
/// 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 func read() throws -> CachedRelays {
do {
return try fileCache.read()
} catch {
if error is DecodingError || (error as? CocoaError)?.code == .fileReadNoSuchFile {
return try readPrebundledRelays()
} else {
throw error
}
}
}
/// Safely write the cache file on disk using file coordinator.
public func write(record: CachedRelays) throws {
try fileCache.write(record)
}
/// Read pre-bundled relays file from disk.
private func readPrebundledRelays() throws -> CachedRelays {
guard let prebundledRelaysFileURL = Bundle(for: Self.self).url(forResource: "relays", withExtension: "json")
else { throw CocoaError(.fileNoSuchFile) }
let data = try Data(contentsOf: prebundledRelaysFileURL)
let relays = try REST.Coding.makeJSONDecoder().decode(REST.ServerRelaysResponse.self, from: data)
return CachedRelays(
relays: relays,
updatedAt: Date(timeIntervalSince1970: 0)
)
}
}