instance_chart/chart/to_vec.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 /// Returns an vector with each discovered node's socketadresses.
9 /// # Note
10 /// - vector order is random
11 /// - only availible for Chart configured with
12 /// [`ChartBuilder::with_service_ports`](crate::ChartBuilder::with_service_ports)
13 /// and build using [`ChartBuilder::finish`](crate::ChartBuilder::finish).
14 /// ```rust
15 /// # use std::error::Error;
16 /// # use instance_chart::{discovery, ChartBuilder};
17 /// #
18 /// # #[tokio::main]
19 /// # async fn main() -> Result<(), Box<dyn Error>> {
20 /// let chart = ChartBuilder::new()
21 /// .with_id(1)
22 /// # .with_discovery_port(43785)
23 /// .with_service_ports([8042, 8043, 8044])
24 /// .finish()?;
25 /// let maintain = discovery::maintain(chart.clone());
26 /// let _ = tokio::spawn(maintain); // maintain task will run forever
27 /// let port_lists = chart.addr_lists_vec();
28 /// # Ok(())
29 /// # }
30 /// ```
31
32 // lock poisoning happens only on crash in another thread, in which
33 // case panicing here is expected
34 #[allow(clippy::missing_panics_doc)]
35 #[must_use]
36 pub fn addr_lists_vec(&self) -> Vec<(Id, [SocketAddr; N])> {
37 self.map
38 .lock()
39 .unwrap()
40 .iter()
41 .map(|(id, entry)| {
42 let Entry { ip, msg: ports } = entry;
43 let addr = ports.map(|p| SocketAddr::new(*ip, p));
44 (*id, addr)
45 })
46 .collect()
47 }
48}
49
50impl<const N: usize> Chart<N, Port> {
51 /// Returns a vector over each discoverd node's nth-socketadress
52 /// # Note
53 /// - vector order is random
54 /// - only availible for Chart configured with
55 /// [`ChartBuilder::with_service_ports`](crate::ChartBuilder::with_service_ports)
56 /// and build using [`ChartBuilder::finish`](crate::ChartBuilder::finish).
57 ///
58 /// # Examples
59 /// ```rust
60 /// # use std::error::Error;
61 /// # use instance_chart::{discovery, ChartBuilder};
62 /// #
63 /// # #[tokio::main]
64 /// # async fn main() -> Result<(), Box<dyn Error>> {
65 /// let web_server_port = 8043;
66 /// let chart = ChartBuilder::new()
67 /// .with_id(1)
68 /// # .with_discovery_port(43784)
69 /// .with_service_ports([8042, web_server_port, 8044])
70 /// .finish()?;
71 /// let maintain = discovery::maintain(chart.clone());
72 /// let _ = tokio::spawn(maintain); // maintain task will run forever
73 /// let web_server_ports = chart.nth_addr_vec::<2>();
74 /// # Ok(())
75 /// # }
76 /// ```
77
78 // lock poisoning happens only on crash in another thread, in which
79 // case panicing here is expected
80 #[allow(clippy::missing_panics_doc)]
81 #[must_use]
82 pub fn nth_addr_vec<const IDX: usize>(&self) -> Vec<(Id, SocketAddr)> {
83 self.map
84 .lock()
85 .unwrap()
86 .iter()
87 .map(|(id, entry)| {
88 let Entry { ip, msg: ports } = entry;
89 let port = ports[IDX];
90 (*id, SocketAddr::new(*ip, port))
91 })
92 .collect()
93 }
94}
95
96impl<'a> Chart<1, Port> {
97 /// Returns a vector over each discoverd nodes's socketadress
98 /// # Note
99 /// - vector order is random
100 /// - only availible for Chart configured with
101 /// [`ChartBuilder::with_service_port`](crate::ChartBuilder::with_service_port)
102 /// and build using [`ChartBuilder::finish`](crate::ChartBuilder::finish).
103 /// ```rust
104 /// # use std::error::Error;
105 /// # use instance_chart::{discovery, ChartBuilder};
106 /// #
107 /// # #[tokio::main]
108 /// # async fn main() -> Result<(), Box<dyn Error>> {
109 /// let chart = ChartBuilder::new()
110 /// .with_id(1)
111 /// # .with_discovery_port(43782)
112 /// .with_service_port(8042)
113 /// .finish()?;
114 /// let maintain = discovery::maintain(chart.clone());
115 /// let _ = tokio::spawn(maintain); // maintain task will run forever
116 /// let ports = chart.addr_vec();
117 /// # Ok(())
118 /// # }
119 /// ```
120
121 // lock poisoning happens only on crash in another thread, in which
122 // case panicing here is expected
123 #[allow(clippy::missing_panics_doc)]
124 #[must_use]
125 pub fn addr_vec(&'a self) -> Vec<(Id, SocketAddr)> {
126 self.map
127 .lock()
128 .unwrap()
129 .iter()
130 .map(|(id, entry)| {
131 let Entry { ip, msg: [port] } = entry;
132 (*id, SocketAddr::new(*ip, *port))
133 })
134 .collect()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use crate::chart::{Entry, Interval};
141 use crate::{Chart, Id};
142 use serde::Serialize;
143 use std::collections::{HashMap, HashSet};
144 use std::fmt::Debug;
145 use std::net::{IpAddr, Ipv4Addr, SocketAddr};
146 use std::sync::{Arc, Mutex};
147 use tokio::net::UdpSocket;
148
149 impl<const N: usize, T: Serialize + Debug + Clone> Chart<N, T> {
150 pub async fn test<F>(mut gen_kv: F) -> Self
151 where
152 F: FnMut(u8) -> (Id, Entry<[T; N]>) + Copy,
153 {
154 let msg = gen_kv(0).1.msg;
155 let map: HashMap<Id, Entry<_>> = (1..10).map(gen_kv).collect();
156 Self {
157 header: 0,
158 service_id: 0,
159 msg,
160 sock: Arc::new(UdpSocket::bind("127.0.0.1:0").await.unwrap()),
161 interval: Interval::test(),
162 map: Arc::new(Mutex::new(map)),
163 broadcast: tokio::sync::broadcast::channel(1).0,
164 }
165 }
166 }
167
168 #[tokio::test]
169 async fn iter_ports() {
170 fn test_kv(n: u8) -> (Id, Entry<[u16; 1]>) {
171 let ip = IpAddr::V4(Ipv4Addr::new(n, 0, 0, 1));
172 let port = 8000 + n as u16;
173 (n as u64, Entry { ip, msg: [port] })
174 }
175
176 let chart = Chart::test(test_kv).await;
177 let iter: HashSet<_> = chart.addr_vec().into_iter().collect();
178 let correct: HashSet<_> = (1..10)
179 .map(test_kv)
180 .map(|(id, e)| (id, SocketAddr::new(e.ip, e.msg[0])))
181 .collect();
182
183 assert_eq!(iter, correct)
184 }
185
186 fn entry_3ports(n: u8) -> (Id, Entry<[u16; 3]>) {
187 let ip = IpAddr::V4(Ipv4Addr::new(n, 0, 0, 1));
188 let port1 = 8000 + n as u16;
189 let port2 = 7000 + n as u16;
190 let port3 = 6000 + n as u16;
191 (
192 n as u64,
193 Entry {
194 ip,
195 msg: [port1, port2, port3],
196 },
197 )
198 }
199
200 #[tokio::test]
201 async fn iter_addr_lists() {
202 let chart = Chart::test(entry_3ports).await;
203 let iter: HashSet<_> = chart.addr_lists_vec().into_iter().collect();
204 let correct: HashSet<_> = (1..10)
205 .map(entry_3ports)
206 .map(|(id, e)| {
207 let addr = e.msg.map(|p| (e.ip, p)).map(SocketAddr::from);
208 (id, addr)
209 })
210 .collect();
211 assert_eq!(iter, correct)
212 }
213 #[tokio::test]
214 async fn iter_nth_port() {
215 let chart = Chart::test(entry_3ports).await;
216 let iter: HashSet<_> = chart.nth_addr_vec::<1>().into_iter().collect();
217 let correct: HashSet<_> = (1..10)
218 .map(entry_3ports)
219 .map(|(id, e)| (id, SocketAddr::new(e.ip, e.msg[1])))
220 .collect();
221 assert_eq!(iter, correct)
222 }
223}