summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadREST/Relay/RelayWithLocation.swift
blob: 85549b79984f9f8b403a78a85561cab699fab435 (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
//
//  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)
    }
}