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
|
//
// RelayWithLocation.swift
// MullvadREST
//
// Created by Mojgan on 2024-05-17.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import Foundation
import MullvadTypes
public struct RelayWithLocation<T: AnyRelay & Sendable>: Sendable {
public let relay: T
public let serverLocation: Location
public func matches(location: RelayLocation) -> Bool {
return switch location {
case let .country(countryCode):
serverLocation.countryCode == countryCode
case let .city(countryCode, cityCode):
serverLocation.countryCode == countryCode && serverLocation.cityCode == cityCode
case let .hostname(countryCode, cityCode, hostname):
serverLocation.countryCode == countryCode && serverLocation.cityCode == cityCode
&& relay.hostname == hostname
}
}
init(relay: T, serverLocation: Location) {
self.relay = relay
self.serverLocation = serverLocation
}
init?(_ relay: T, locations: [String: REST.ServerLocation]) {
guard
let serverLocation = locations[relay.location.rawValue]
else { return nil }
self.relay = relay
self.serverLocation = Location(
country: serverLocation.country,
countryCode: String(relay.location.country),
city: serverLocation.city,
cityCode: String(relay.location.city),
latitude: serverLocation.latitude,
longitude: serverLocation.longitude
)
}
/// given a list of `AnyRelay` values and a name to location mapping, produce a list of
/// `RelayWithLocation`values for those whose locations have successfully been found.
public static func locateRelays(
relays: [T],
locations: [String: REST.ServerLocation]
) -> [RelayWithLocation<T>] {
relays.compactMap { RelayWithLocation($0, locations: locations) }
}
}
extension RelayWithLocation: Hashable {
public static func == (lhs: RelayWithLocation<T>, rhs: RelayWithLocation<T>) -> Bool {
lhs.relay.hostname == rhs.relay.hostname
}
public func hash(into hasher: inout Hasher) {
hasher.combine(relay.hostname)
}
}
|