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}