# iroh-topic-tracker
[](https://crates.io/crates/iroh-topic-tracker)
[](https://docs.rs/iroh-topic-tracker)
**A tracker for Iroh NodeId's in GossipSub topics.**
This library integrates with
[`iroh-gossip`](https://crates.io/crates/iroh-gossip) to automate peer
discovery and includes a hosted `BOOTSTRAP_NODE` for seamless topic tracking
without you needing to host anything. Your peers can discover each other even
if both are behind NATs.
---
## Overview
The crate provides a
[`TopicTracker`](https://docs.rs/iroh-topic-tracker/latest/iroh_topic_tracker/topic_tracker/struct.TopicTracker.html)
to manage and discover peers participating in shared GossipSub topics. It
leverages Iroh's direct connectivity and
[`Router`](https://docs.rs/iroh/latest/iroh/protocol/struct.Router.html) to
handle protocol routing.
### Features
- Automatic peer discovery via `iroh-gossip` (enabled with
`iroh-gossip-auto-discovery` feature).
- Dedicated bootstrap node support for topic tracking.
- Simple API to fetch active peers for a topic.
---
## Getting Started
### Prerequisites
Add the crate to your `Cargo.toml` with the required features:
```toml
[dependencies]
iroh-topic-tracker = { version = "0.1", features = ["iroh-gossip-auto-discovery"] }
```
### Automatic Discovery
Enable `iroh-gossip` integration to automate peer discovery for topics:
```rust
use futures_lite::StreamExt;
use iroh::Endpoint;
use iroh_gossip::net::{Event, Gossip, GossipEvent};
use iroh_topic_tracker::{integrations::iroh_gossip::*, topic_tracker::Topic};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Configure Iroh endpoint with discovery
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
// Configure gossip protocol with auto-discovery
let gossip = Gossip::builder()
.spawn_with_auto_discovery(endpoint.clone())
.await?;
// Join a topic and start tracking
let topic = Topic::from_passphrase("my-iroh-gossip-topic");
let (sink, mut stream) = gossip.subscribe_and_join(topic.into()).await?.split();
// Read from stream ..
while let Some(event) = stream.next().await {
if let Ok(Event::Gossip(GossipEvent::Received(msg))) = event {
// Do something with msg...
let msg_text = String::from_utf8(msg.content.to_vec()).unwrap();
}
}
// .. or Send to Sink
sink.broadcast("my msg goes here".into()).await.unwrap();
Ok(())
}
```
### Basic Setup with Iroh
```rust
use iroh::{protocol::Router, Endpoint};
use iroh_topic_tracker::topic_tracker::{Topic, TopicTracker};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Configure Iroh endpoint with discovery
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
// Initialize topic tracker
let topic_tracker = TopicTracker::new(&endpoint);
// Attach to Iroh router
let router = Router::builder(endpoint.clone())
.accept(TopicTracker::ALPN, topic_tracker.clone())
.spawn()
.await?;
// Track peers in a topic
let topic = Topic::from_passphrase("my-secret-topic");
let peers = topic_tracker.get_topic_nodes(&topic).await?;
Ok(())
}
```
---
## Examples
### Run a Topic Tracker Node
Start a dedicated tracker node:
```bash
cargo run --example server
```
*Note: Update `secret.rs` with your `SecretKey` and configure `BOOTSTRAP_NODES`
in `topic_tracker.rs` for secure communication.*
### Query Active Peers
Fetch the latest NodeIds for a topic:
```bash
cargo run --example client
```
---
## Building
Optimized release build for the tracker server:
```bash
cargo build --release --example server
```
---
## License
This project is licensed under either of
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE.txt) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT.txt) or
<http://opensource.org/licenses/MIT>)
at your option.
### Contribution
Unless explicitly stated, any contribution intentionally submitted for
inclusion in this project shall be dual-licensed as above, without any
additional terms or conditions.