blob: 1e52f1dc52093405b7a2bb45c9cf5be1c3e4783c (
plain)
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
//
// IPOverrideRepository.swift
// MullvadVPN
//
// Created by Jon Petersson on 2024-01-16.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
@preconcurrency import Combine
import MullvadLogging
public protocol IPOverrideRepositoryProtocol: Sendable {
var overridesPublisher: AnyPublisher<[IPOverride], Never> { get }
func add(_ overrides: [IPOverride])
func fetchAll() -> [IPOverride]
func deleteAll()
func parse(data: Data) throws -> [IPOverride]
}
public final class IPOverrideRepository: IPOverrideRepositoryProtocol {
private let overridesSubject: CurrentValueSubject<[IPOverride], Never> = .init([])
public var overridesPublisher: AnyPublisher<[IPOverride], Never> {
overridesSubject.eraseToAnyPublisher()
}
nonisolated(unsafe) private let logger = Logger(label: "IPOverrideRepository")
private let readWriteLock = NSLock()
public init() {}
public func add(_ overrides: [IPOverride]) {
var storedOverrides = fetchAll()
overrides.forEach { override in
if let existingOverrideIndex = storedOverrides.firstIndex(where: { $0.hostname == override.hostname }) {
var existingOverride = storedOverrides[existingOverrideIndex]
if let ipv4Address = override.ipv4Address {
existingOverride.ipv4Address = ipv4Address
}
if let ipv6Address = override.ipv6Address {
existingOverride.ipv6Address = ipv6Address
}
storedOverrides[existingOverrideIndex] = existingOverride
} else {
storedOverrides.append(override)
}
}
do {
try writeIpOverrides(storedOverrides)
} catch {
logger.error("Could not add override(s): \(overrides) \nError: \(error)")
}
}
public func fetchAll() -> [IPOverride] {
return (try? readIpOverrides()) ?? []
}
public func deleteAll() {
do {
try readWriteLock.withLock {
try SettingsManager.store.delete(key: .ipOverrides)
overridesSubject.send([])
}
} catch {
logger.error("Could not delete all overrides. \nError: \(error)")
}
}
public func parse(data: Data) throws -> [IPOverride] {
let decoder = JSONDecoder()
let jsonData = try decoder.decode(RelayOverrides.self, from: data)
return jsonData.overrides
}
private func readIpOverrides() throws -> [IPOverride] {
try readWriteLock.withLock {
let parser = makeParser()
let data = try SettingsManager.store.read(key: .ipOverrides)
return try parser.parseUnversionedPayload(as: [IPOverride].self, from: data)
}
}
private func writeIpOverrides(_ overrides: [IPOverride]) throws {
let parser = makeParser()
let data = try parser.produceUnversionedPayload(overrides)
try readWriteLock.withLock {
try SettingsManager.store.write(data, for: .ipOverrides)
overridesSubject.send(overrides)
}
}
private func makeParser() -> SettingsParser {
SettingsParser(decoder: JSONDecoder(), encoder: JSONEncoder())
}
}
|