veilid_core/routing_table/types/
signed_node_info.rs

1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
4pub enum SignedNodeInfo {
5    Direct(SignedDirectNodeInfo),
6    Relayed(SignedRelayedNodeInfo),
7}
8
9impl fmt::Display for SignedNodeInfo {
10    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11        match self {
12            Self::Direct(arg0) => {
13                writeln!(f, "direct:")?;
14                write!(f, "{}", indent_all_string(arg0))?;
15                Ok(())
16            }
17            Self::Relayed(arg0) => {
18                writeln!(f, "relayed:")?;
19                write!(f, "{}", indent_all_string(&arg0))?;
20                Ok(())
21            }
22        }
23    }
24}
25
26impl SignedNodeInfo {
27    pub fn validate(
28        &self,
29        node_ids: &TypedNodeIdGroup,
30        crypto: &Crypto,
31    ) -> VeilidAPIResult<TypedNodeIdGroup> {
32        match self {
33            SignedNodeInfo::Direct(d) => d.validate(node_ids, crypto),
34            SignedNodeInfo::Relayed(r) => r.validate(node_ids, crypto),
35        }
36    }
37
38    pub fn has_any_signature(&self) -> bool {
39        match self {
40            SignedNodeInfo::Direct(d) => d.has_any_signature(),
41            SignedNodeInfo::Relayed(r) => r.has_any_signature(),
42        }
43    }
44
45    pub fn timestamp(&self) -> Timestamp {
46        match self {
47            SignedNodeInfo::Direct(d) => d.timestamp(),
48            SignedNodeInfo::Relayed(r) => r.timestamp(),
49        }
50    }
51    pub fn node_info(&self) -> &NodeInfo {
52        match self {
53            SignedNodeInfo::Direct(d) => d.node_info(),
54            SignedNodeInfo::Relayed(r) => r.node_info(),
55        }
56    }
57    pub fn relay_ids(&self) -> TypedNodeIdGroup {
58        match self {
59            SignedNodeInfo::Direct(_) => TypedNodeIdGroup::new(),
60            SignedNodeInfo::Relayed(r) => r.relay_ids().clone(),
61        }
62    }
63    pub fn relay_info(&self) -> Option<&NodeInfo> {
64        match self {
65            SignedNodeInfo::Direct(_) => None,
66            SignedNodeInfo::Relayed(r) => Some(r.relay_info().node_info()),
67        }
68    }
69    pub fn relay_peer_info(&self, routing_domain: RoutingDomain) -> Option<Arc<PeerInfo>> {
70        match self {
71            SignedNodeInfo::Direct(_) => None,
72            SignedNodeInfo::Relayed(r) => Some(Arc::new(
73                PeerInfo::new(
74                    routing_domain,
75                    r.relay_ids().clone(),
76                    SignedNodeInfo::Direct(r.relay_info().clone()),
77                )
78                .unwrap(), // validate() above, should have ensured this succeeds
79            )),
80        }
81    }
82    pub fn has_any_dial_info(&self) -> bool {
83        self.node_info().has_dial_info()
84            || self
85                .relay_info()
86                .map(|relay_ni| relay_ni.has_dial_info())
87                .unwrap_or_default()
88    }
89
90    pub fn has_sequencing_matched_dial_info(&self, sequencing: Sequencing) -> bool {
91        // Check our dial info
92        for did in self.node_info().dial_info_detail_list() {
93            match sequencing {
94                Sequencing::NoPreference | Sequencing::PreferOrdered => return true,
95                Sequencing::EnsureOrdered => {
96                    if did.dial_info.protocol_type().is_ordered() {
97                        return true;
98                    }
99                }
100            }
101        }
102        // Check our relay if we have one
103        self.relay_info()
104            .map(|relay_ni| {
105                for did in relay_ni.dial_info_detail_list() {
106                    match sequencing {
107                        Sequencing::NoPreference | Sequencing::PreferOrdered => return true,
108                        Sequencing::EnsureOrdered => {
109                            if did.dial_info.protocol_type().is_ordered() {
110                                return true;
111                            }
112                        }
113                    }
114                }
115                false
116            })
117            .unwrap_or_default()
118    }
119
120    #[cfg(feature = "geolocation")]
121    /// Get geolocation info of node and its relays.
122    pub fn get_geolocation_info(&self, routing_domain: RoutingDomain) -> GeolocationInfo {
123        if routing_domain != RoutingDomain::PublicInternet {
124            // Country code is irrelevant for local network
125            return GeolocationInfo::new(None, vec![]);
126        }
127
128        let get_node_country_code = |node_info: &NodeInfo| {
129            let country_codes = node_info
130                .dial_info_detail_list()
131                .iter()
132                .map(|did| match &did.dial_info {
133                    DialInfo::UDP(di) => di.socket_address.ip_addr(),
134                    DialInfo::TCP(di) => di.socket_address.ip_addr(),
135                    DialInfo::WS(di) => di.socket_address.ip_addr(),
136                    DialInfo::WSS(di) => di.socket_address.ip_addr(),
137                })
138                .map(geolocation::query_country_code)
139                .collect::<Vec<_>>();
140
141            if country_codes.is_empty() {
142                return None;
143            }
144
145            // Indexing cannot panic, guarded by a check above
146            let cc0 = country_codes[0];
147
148            if !country_codes.iter().all(|cc| cc.is_some() && *cc == cc0) {
149                // Lookup failed for some address or results are different
150                return None;
151            }
152
153            cc0
154        };
155
156        match self {
157            SignedNodeInfo::Direct(sni) => {
158                GeolocationInfo::new(get_node_country_code(sni.node_info()), vec![])
159            }
160            SignedNodeInfo::Relayed(sni) => {
161                let relay_cc = get_node_country_code(sni.relay_info().node_info());
162
163                GeolocationInfo::new(get_node_country_code(sni.node_info()), vec![relay_cc])
164            }
165        }
166    }
167
168    /// Compare this SignedNodeInfo to another one
169    /// Exclude the signature and timestamp and any other fields that are not
170    /// semantically valuable
171    pub fn equivalent(&self, other: &SignedNodeInfo) -> bool {
172        match self {
173            SignedNodeInfo::Direct(d) => match other {
174                SignedNodeInfo::Direct(pd) => d.equivalent(pd),
175                SignedNodeInfo::Relayed(_) => false,
176            },
177            SignedNodeInfo::Relayed(r) => match other {
178                SignedNodeInfo::Direct(_) => false,
179                SignedNodeInfo::Relayed(pr) => r.equivalent(pr),
180            },
181        }
182    }
183}