Skip to main content

chat/
chat.rs

1use anyhow::Result;
2use iroh::{Endpoint, SecretKey};
3use iroh_gossip::{api::Event, net::Gossip};
4
5use ed25519_dalek::SigningKey;
6
7// Imports from distributed-topic-tracker
8use distributed_topic_tracker::{
9    AutoDiscoveryGossip, BootstrapConfig, Config, RecordPublisher, TopicId,
10};
11
12#[tokio::main]
13async fn main() -> Result<()> {
14    // tracing init - only show distributed_topic_tracker logs
15    use tracing_subscriber::filter::EnvFilter;
16
17    tracing_subscriber::fmt()
18        .with_thread_ids(true)
19        .with_ansi(true)
20        .with_env_filter(
21            EnvFilter::try_from_default_env()
22                .unwrap_or_else(|_| EnvFilter::new("distributed_topic_tracker=debug")),
23        )
24        .init();
25
26    // Generate a new random secret key
27    let secret_key = SecretKey::generate();
28    let signing_key = SigningKey::from_bytes(&secret_key.to_bytes());
29
30    // Set up endpoint with discovery enabled
31    let endpoint = Endpoint::builder(iroh::endpoint::presets::N0)
32        .secret_key(secret_key.clone())
33        .bind()
34        .await?;
35
36    // Initialize gossip with auto-discovery
37    let gossip = Gossip::builder().spawn(endpoint.clone());
38
39    // Set up protocol router
40    let _router = iroh::protocol::Router::builder(endpoint.clone())
41        .accept(iroh_gossip::ALPN, gossip.clone())
42        .spawn();
43
44    let topic_id = TopicId::new("my-iroh-gossip-topic".to_string());
45    let initial_secret = b"my-initial-secret".to_vec();
46
47    let record_publisher = RecordPublisher::new(
48        topic_id.clone(),
49        signing_key.clone(),
50        None,
51        initial_secret,
52        Config::builder()
53            .bootstrap_config(
54                BootstrapConfig::builder()
55                    .check_older_records_first_on_startup(false)
56                    .build(),
57            )
58            .build(),
59    );
60
61    // Split into sink (sending) and stream (receiving)
62    let (gossip_sender, mut gossip_receiver) = gossip
63        .subscribe_and_join_with_auto_discovery(record_publisher)
64        .await?
65        .split()
66        .await?;
67
68    println!("Joined topic");
69
70    // Spawn listener for incoming messages
71    tokio::spawn(async move {
72        while let Ok(event) = gossip_receiver.next().await {
73            if let Event::Received(msg) = event {
74                println!(
75                    "\nMessage from {}: {}",
76                    &msg.delivered_from.to_string()[0..8],
77                    String::from_utf8(msg.content.to_vec()).unwrap()
78                );
79            } else if let Event::NeighborUp(peer) = event {
80                println!("\nJoined by {}", &peer.to_string()[0..8]);
81            }
82        }
83        println!("\nGossip receiver stream ended");
84    });
85
86    // Main input loop for sending messages
87    let mut buffer = String::new();
88    let stdin = std::io::stdin();
89    loop {
90        print!("\n> ");
91        stdin.read_line(&mut buffer).unwrap();
92        gossip_sender
93            .broadcast(
94                buffer
95                    .trim_end_matches(&['\r', '\n'][..])
96                    .as_bytes()
97                    .to_vec(),
98            )
99            .await
100            .unwrap();
101        println!(" - (sent)");
102        buffer.clear();
103    }
104}