instance_chart/chart/get.rs
1use crate::Id;
2use std::net::SocketAddr;
3
4use super::builder::Port;
5use super::{Chart, Entry};
6
7impl<const N: usize> Chart<N, Port> {
8 /// Get all the `SocketAddr`'s for a given node's `Id`
9 ///
10 /// # Note
11 /// returns None if the node was not in the Chart
12 ///
13 /// # Performance
14 /// This locks the map. if you need adresses for many nodes
15 /// is faster to get a vector of them at once [`Self::addr_lists_vec()`]
16 /// instead of calling this repeatedly
17 ///
18 /// # Panics
19 /// This function panics when called with the `Id` of the chart instance
20 /// it is called on
21 ///
22 /// # Examples
23 /// ```rust
24 /// # use std::error::Error;
25 /// # use instance_chart::{discovery, ChartBuilder};
26 /// #
27 /// # #[tokio::main]
28 /// # async fn main() -> Result<(), Box<dyn Error>> {
29 /// let service_ports = [8042, 8043, 8044];
30 /// let chart = ChartBuilder::new()
31 /// .with_id(1)
32 /// # .with_discovery_port(43794)
33 /// .with_service_ports(service_ports)
34 /// .finish()?;
35 /// let maintain = discovery::maintain(chart.clone());
36 /// let _ = tokio::spawn(maintain); // maintain task will run forever
37 /// let from_chart = chart.get_addr_list(2);
38 /// assert_eq!(None, from_chart);
39 /// # Ok(())
40 /// # }
41 /// ```
42
43 // lock poisoning happens only on crash in another thread, in which
44 // case panicing here is expected
45 #[must_use]
46 pub fn get_addr_list(&self, id: Id) -> Option<[SocketAddr; N]> {
47 assert_ne!(self.our_id(), id, "Can not call with our own id");
48 let map = self.map.lock().unwrap();
49 let Entry { ip, msg: ports } = map.get(&id)?;
50 let arr = ports.map(|p| SocketAddr::new(*ip, p));
51 Some(arr)
52 }
53}
54
55impl<const N: usize> Chart<N, Port> {
56 /// Get a nodes nth `SocketAddr`'s given its `Id`
57 ///
58 /// # Note
59 /// returns None if the node was not in the Chart
60 ///
61 /// # Panics
62 /// This function panics when called with the `Id` of the chart instance
63 /// it is called on
64 ///
65 /// # Performance
66 /// This locks the map. if you need adresses for many nodes
67 /// is faster to get a vector of them at once [`Self::addr_lists_vec()`]
68 /// instead of calling this repeatedly
69 ///
70 /// # Examples
71 /// ```rust
72 /// # use std::error::Error;
73 /// # use instance_chart::{discovery, ChartBuilder};
74 /// #
75 /// # #[tokio::main]
76 /// # async fn main() -> Result<(), Box<dyn Error>> {
77 /// let port = 8043;
78 /// let chart = ChartBuilder::new()
79 /// .with_id(1)
80 /// # .with_discovery_port(43794)
81 /// .with_service_ports([8042, port, 8044])
82 /// .finish()?;
83 /// let maintain = discovery::maintain(chart.clone());
84 /// let _ = tokio::spawn(maintain); // maintain task will run forever
85 /// let from_chart = chart.get_nth_addr::<2>(2);
86 /// assert_eq!(None, from_chart);
87 /// # Ok(())
88 /// # }
89 /// ```
90
91 // lock poisoning happens only on crash in another thread, in which
92 // case panicing here is expected
93 #[must_use]
94 pub fn get_nth_addr<const IDX: usize>(&self, id: Id) -> Option<SocketAddr> {
95 assert_ne!(self.our_id(), id, "Can not call with our own id");
96 let map = self.map.lock().unwrap();
97 let Entry { ip, msg: ports } = map.get(&id)?;
98 let port = ports[IDX];
99 Some(SocketAddr::new(*ip, port))
100 }
101}
102
103impl Chart<1, Port> {
104 /// Get a nodes `SocketAddr`'s given its `Id`
105 ///
106 /// # Note
107 /// returns None if the node was not in the Chart
108 ///
109 /// # Panics
110 /// This function panics when called with the `Id` of the chart instance
111 /// it is called on
112 ///
113 /// # Performance
114 /// This locks the map. if you need adresses for many nodes
115 /// is faster to get a vector of them at once [`Self::addr_lists_vec()`]
116 /// instead of calling this repeatedly
117 ///
118 /// # Examples
119 /// ```rust
120 /// # use std::error::Error;
121 /// # use instance_chart::{discovery, ChartBuilder};
122 /// #
123 /// # #[tokio::main]
124 /// # async fn main() -> Result<(), Box<dyn Error>> {
125 /// let port = 8043;
126 /// let chart = ChartBuilder::new()
127 /// .with_id(1)
128 /// # .with_discovery_port(43794)
129 /// .with_service_ports([port])
130 /// .finish()?;
131 /// let maintain = discovery::maintain(chart.clone());
132 /// let _ = tokio::spawn(maintain); // maintain task will run forever
133 /// let from_chart = chart.get_addr(2);
134 /// assert_eq!(None, from_chart);
135 /// # Ok(())
136 /// # }
137 /// ```
138
139 // lock poisoning happens only on crash in another thread, in which
140 // case panicing here is expected
141 #[must_use]
142 pub fn get_addr(&self, id: Id) -> Option<SocketAddr> {
143 assert_ne!(self.our_id(), id, "Can not call with our own id");
144 let map = self.map.lock().unwrap();
145 let Entry { ip, msg: [port] } = map.get(&id)?;
146 Some(SocketAddr::new(*ip, *port))
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use crate::chart::Entry;
153 use crate::{Chart, Id};
154 use std::net::{IpAddr, Ipv4Addr, SocketAddr};
155
156 #[tokio::test]
157 async fn get_addr_list() {
158 fn test_kv(n: u8) -> (Id, Entry<[u16; 1]>) {
159 let ip = IpAddr::V4(Ipv4Addr::new(n, 0, 0, 1));
160 let port = 8000 + n as u16;
161 (n as u64, Entry { ip, msg: [port] })
162 }
163
164 let chart = Chart::test(test_kv).await;
165 let iter = chart.get_addr_list(2).unwrap();
166 let entry = test_kv(2).1;
167 let correct = [SocketAddr::new(entry.ip, entry.msg[0])];
168
169 assert_eq!(iter, correct)
170 }
171
172 fn entry_3ports(n: u8) -> (Id, Entry<[u16; 3]>) {
173 let ip = IpAddr::V4(Ipv4Addr::new(n, 0, 0, 1));
174 let port1 = 8000 + n as u16;
175 let port2 = 7000 + n as u16;
176 let port3 = 6000 + n as u16;
177 (
178 n as u64,
179 Entry {
180 ip,
181 msg: [port1, port2, port3],
182 },
183 )
184 }
185
186 #[tokio::test]
187 async fn get_nth_addr() {
188 let chart = Chart::test(entry_3ports).await;
189 let addr = chart.get_nth_addr::<2>(2).unwrap();
190 let entry = entry_3ports(2).1;
191 let correct = SocketAddr::new(entry.ip, entry.msg[2]);
192 assert_eq!(addr, correct)
193 }
194}