1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use crate::behaviour::{ExpiredListenAddr, FromSwarm, NewListenAddr};
use libp2p_core::Multiaddr;
use std::collections::HashSet;

/// Utility struct for tracking the addresses a [`Swarm`](crate::Swarm) is listening on.
#[derive(Debug, Default, Clone)]
pub struct ListenAddresses {
    addresses: HashSet<Multiaddr>,
}

impl ListenAddresses {
    /// Returns an [`Iterator`] over all listen addresses.
    pub fn iter(&self) -> impl ExactSizeIterator<Item = &Multiaddr> {
        self.addresses.iter()
    }

    /// Feed a [`FromSwarm`] event to this struct.
    ///
    /// Returns whether the event changed our set of listen addresses.
    pub fn on_swarm_event<THandler>(&mut self, event: &FromSwarm<THandler>) -> bool {
        match event {
            FromSwarm::NewListenAddr(NewListenAddr { addr, .. }) => {
                self.addresses.insert((*addr).clone())
            }
            FromSwarm::ExpiredListenAddr(ExpiredListenAddr { addr, .. }) => {
                self.addresses.remove(addr)
            }
            _ => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::dummy;
    use libp2p_core::{multiaddr::Protocol, transport::ListenerId};
    use once_cell::sync::Lazy;

    #[test]
    fn new_listen_addr_returns_correct_changed_value() {
        let mut addresses = ListenAddresses::default();

        let changed = addresses.on_swarm_event(&new_listen_addr());
        assert!(changed);

        let changed = addresses.on_swarm_event(&new_listen_addr());
        assert!(!changed)
    }

    #[test]
    fn expired_listen_addr_returns_correct_changed_value() {
        let mut addresses = ListenAddresses::default();
        addresses.on_swarm_event(&new_listen_addr());

        let changed = addresses.on_swarm_event(&expired_listen_addr());
        assert!(changed);

        let changed = addresses.on_swarm_event(&expired_listen_addr());
        assert!(!changed)
    }

    fn new_listen_addr() -> FromSwarm<'static, dummy::ConnectionHandler> {
        FromSwarm::NewListenAddr(NewListenAddr {
            listener_id: ListenerId::next(),
            addr: &MEMORY_ADDR,
        })
    }

    fn expired_listen_addr() -> FromSwarm<'static, dummy::ConnectionHandler> {
        FromSwarm::ExpiredListenAddr(ExpiredListenAddr {
            listener_id: ListenerId::next(),
            addr: &MEMORY_ADDR,
        })
    }

    static MEMORY_ADDR: Lazy<Multiaddr> =
        Lazy::new(|| Multiaddr::empty().with(Protocol::Memory(1000)));
}