1use std::{
3 fmt::{self, Debug, Formatter},
4 net::SocketAddrV4,
5 sync::Arc,
6 time::{Duration, Instant},
7};
8
9use crate::common::Id;
10
11pub const STALE_TIME: Duration = Duration::from_secs(15 * 60);
14const MIN_PING_BACKOFF_INTERVAL: Duration = Duration::from_secs(10);
15pub const TOKEN_ROTATE_INTERVAL: Duration = Duration::from_secs(60 * 5);
16
17#[derive(PartialEq)]
18pub(crate) struct NodeInner {
19 pub(crate) id: Id,
20 pub(crate) address: SocketAddrV4,
21 pub(crate) token: Option<Box<[u8]>>,
22 pub(crate) last_seen: Instant,
23}
24
25impl NodeInner {
26 pub fn random() -> Self {
27 Self {
28 id: Id::random(),
29 address: SocketAddrV4::new(0.into(), 0),
30 token: None,
31 last_seen: Instant::now(),
32 }
33 }
34}
35
36#[derive(Clone, PartialEq)]
37pub struct Node(pub(crate) Arc<NodeInner>);
39
40impl Debug for Node {
41 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
42 fmt.debug_struct("Node")
43 .field("id", &self.0.id)
44 .field("address", &self.0.address)
45 .field("last_seen", &self.0.last_seen.elapsed().as_secs())
46 .finish()
47 }
48}
49
50impl Node {
51 pub fn new(id: Id, address: SocketAddrV4) -> Node {
53 Node(Arc::new(NodeInner {
54 id,
55 address,
56 token: None,
57 last_seen: Instant::now(),
58 }))
59 }
60
61 pub(crate) fn new_with_token(id: Id, address: SocketAddrV4, token: Box<[u8]>) -> Self {
62 Node(Arc::new(NodeInner {
63 id,
64 address,
65 token: Some(token),
66 last_seen: Instant::now(),
67 }))
68 }
69
70 pub fn random() -> Node {
72 Node(Arc::new(NodeInner::random()))
73 }
74
75 #[cfg(test)]
77 pub fn unique(i: usize) -> Node {
78 Node::new(Id::random(), SocketAddrV4::new((i as u32).into(), i as u16))
79 }
80
81 pub fn id(&self) -> &Id {
85 &self.0.id
86 }
87
88 pub fn address(&self) -> SocketAddrV4 {
90 self.0.address
91 }
92
93 pub fn token(&self) -> Option<Box<[u8]>> {
95 self.0.token.clone()
96 }
97
98 pub fn is_stale(&self) -> bool {
100 self.0.last_seen.elapsed() > STALE_TIME
101 }
102
103 pub fn valid_token(&self) -> bool {
105 self.0.last_seen.elapsed() <= TOKEN_ROTATE_INTERVAL
106 }
107
108 pub(crate) fn should_ping(&self) -> bool {
109 self.0.last_seen.elapsed() > MIN_PING_BACKOFF_INTERVAL
110 }
111
112 pub fn same_address(&self, other: &Self) -> bool {
114 self.0.address == other.0.address
115 }
116
117 pub fn same_ip(&self, other: &Self) -> bool {
119 self.0.address.ip() == other.0.address.ip()
120 }
121
122 pub fn is_secure(&self) -> bool {
126 self.0.id.is_valid_for_ip(*self.0.address.ip())
127 }
128
129 pub(crate) fn already_exists(&self, nodes: &[Self]) -> bool {
136 nodes.iter().any(|existing| {
137 self.same_ip(existing)
138 && (!existing.is_secure()
139 || self.id().first_21_bits() == existing.id().first_21_bits())
140 })
141 }
142}