diff --git a/protocols/gossipsub/CHANGELOG.md b/protocols/gossipsub/CHANGELOG.md index 54bbb7ff..fe700c63 100644 --- a/protocols/gossipsub/CHANGELOG.md +++ b/protocols/gossipsub/CHANGELOG.md @@ -1,5 +1,7 @@ # 0.21.0 [unreleased] +- Add public API to list topics and peers. [PR 1677](https://github.com/libp2p/rust-libp2p/pull/1677). + - Add message signing and extended privacy/validation configurations. [PR 1583](https://github.com/libp2p/rust-libp2p/pull/1583). - `Debug` instance for `Gossipsub`. [PR 1673](https://github.com/libp2p/rust-libp2p/pull/1673). diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index 7636c2c0..5be1fc4f 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -221,6 +221,25 @@ impl Gossipsub { } } + /// Lists the hashes of the topics we are currently subscribed to. + pub fn topics(&self) -> impl Iterator { + self.mesh.keys() + } + + /// Lists peers for a certain topic hash. + pub fn peers(&self, topic_hash: &TopicHash) -> impl Iterator { + self.mesh.get(topic_hash).into_iter().map(|x| x.into_iter()).flatten() + } + + /// Lists all peers for any topic. + pub fn all_peers(&self) -> impl Iterator { + let mut res = BTreeSet::new(); + for peers in self.mesh.values() { + res.extend(peers); + } + res.into_iter() + } + /// Subscribe to a topic. /// /// Returns true if the subscription worked. Returns false if we were already subscribed. @@ -1508,10 +1527,10 @@ impl fmt::Debug for Gossipsub { impl fmt::Debug for PublishConfig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - PublishConfig::Signing { author, .. } => f.write_fmt(format_args!("PublishConfig::Signing({})", author)), - PublishConfig::Author(author) => f.write_fmt(format_args!("PublishConfig::Author({})", author)), - PublishConfig::RandomAuthor => f.write_fmt(format_args!("PublishConfig::RandomAuthor")), - PublishConfig::Anonymous => f.write_fmt(format_args!("PublishConfig::Anonymous")), + PublishConfig::Signing { author, .. } => f.write_fmt(format_args!("PublishConfig::Signing({})", author)), + PublishConfig::Author(author) => f.write_fmt(format_args!("PublishConfig::Author({})", author)), + PublishConfig::RandomAuthor => f.write_fmt(format_args!("PublishConfig::RandomAuthor")), + PublishConfig::Anonymous => f.write_fmt(format_args!("PublishConfig::Anonymous")), } } } diff --git a/protocols/gossipsub/src/behaviour/tests.rs b/protocols/gossipsub/src/behaviour/tests.rs index 73a6a0b2..8fee8161 100644 --- a/protocols/gossipsub/src/behaviour/tests.rs +++ b/protocols/gossipsub/src/behaviour/tests.rs @@ -895,4 +895,27 @@ mod tests { // Peers should be removed to reach mesh_n assert_eq!(gs.mesh.get(&topics[0]).unwrap().len(), config.mesh_n); } + + // Some very basic test of public api methods. + #[test] + fn test_public_api() { + let (gs, peers, topic_hashes) = + build_and_inject_nodes(4, vec![String::from("topic1")], true); + let peers = peers.into_iter().collect::>(); + + assert_eq!( + gs.topics().cloned().collect::>(), topic_hashes, + "Expected topics to match registered topic." + ); + + assert_eq!( + gs.peers(&TopicHash::from_raw("topic1")).cloned().collect::>(), peers, + "Expected peers for a registered topic to contain all peers." + ); + + assert_eq!( + gs.all_peers().cloned().collect::>(), peers, + "Expected all_peers to contain all peers." + ); + } }