### Minimal Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md A minimal setup for iroh-gossip, showing endpoint creation, gossip protocol instantiation, and router setup. ```rust use iroh::{Endpoint, protocol::Router}; use iroh_gossip::{Gossip, ALPN}; #[tokio::main] async fn main() -> anyhow::Result<()> { // Create endpoint let endpoint = Endpoint::bind().await?; // Create gossip protocol let gossip = Gossip::builder().spawn(endpoint.clone()); // Setup router let router = Router::builder(endpoint) .accept(ALPN, gossip.clone()) .spawn(); // ... use gossip ... // Shutdown router.shutdown().await?; Ok(()) } ``` -------------------------------- ### Basic iroh-gossip setup with iroh Source: https://github.com/p2panda/iroh-gossip/blob/main/README.md This example demonstrates how to set up iroh-gossip with iroh, including creating an endpoint, building the gossip protocol, setting up a router, subscribing to a topic, and broadcasting/receiving messages. ```rust use iroh::{protocol::Router, Endpoint, EndpointId}; use iroh_gossip::{api::Event, Gossip, TopicId}; use n0_error::{Result, StdResultExt}; use n0_future::StreamExt; #[tokio::main] async fn main() -> Result<()> { // create an iroh endpoint that includes the standard discovery mechanisms // we've built at number0 let endpoint = Endpoint::bind().await?; // build gossip protocol let gossip = Gossip::builder().spawn(endpoint.clone()); // setup router let router = Router::builder(endpoint) .accept(iroh_gossip::ALPN, gossip.clone()) .spawn(); // gossip swarms are centered around a shared "topic id", which is a 32 byte identifier let topic_id = TopicId::from_bytes([23u8; 32]); // and you need some bootstrap peers to join the swarm let bootstrap_peers = bootstrap_peers(); // then, you can subscribe to the topic and join your initial peers let (sender, mut receiver) = gossip .subscribe(topic_id, bootstrap_peers) .await? .split(); // you might want to wait until you joined at least one other peer: receiver.joined().await?; // then, you can broadcast messages to all other peers! sender.broadcast(b"hello world this is a gossip message".to_vec().into()).await?; // and read messages from others! while let Some(event) = receiver.next().await { match event? { Event::Received(message) => { println!("received a message: {:?}", std::str::from_utf8(&message.content)); } _ => {} } } // clean shutdown makes sure that other peers are notified that you went offline router.shutdown().await.std_context("shutdown router")?; Ok(()) } fn bootstrap_peers() -> Vec { // insert your bootstrap peers here, or get them from your environment vec![] } ``` -------------------------------- ### JoinOptions Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Example of creating and using JoinOptions. ```rust let opts = JoinOptions::with_bootstrap(vec![peer1, peer2]); let topic = gossip.subscribe_with_opts(topic_id, opts).await?; ``` -------------------------------- ### membership_config() Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Example of configuring the membership layer. ```rust let mut membership_config = HyparviewConfig::default(); membership_config.active_view_capacity = 10; // Increase from default 5 let gossip = Gossip::builder() .membership_config(membership_config) .spawn(endpoint); ``` -------------------------------- ### PeerData Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Example of creating PeerData. ```rust let peer_data = PeerData::new(vec![1, 2, 3]); ``` -------------------------------- ### broadcast_config() Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Example of configuring the broadcast layer. ```rust let mut broadcast_config = PlumtreeConfig::default(); broadcast_config.graft_timeout_1 = Duration::from_millis(100); let gossip = Gossip::builder() .broadcast_config(broadcast_config) .spawn(endpoint); ``` -------------------------------- ### JoinOptions Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Example of creating JoinOptions with initial bootstrap peers and customizing subscription capacity. ```rust use iroh_gossip::api::JoinOptions; let mut opts = JoinOptions::with_bootstrap(vec![peer1, peer2]); // Customize capacity for slow consumers // opts.subscription_capacity = 4096; let topic = gossip.subscribe_with_opts(topic_id, opts).await?; ``` -------------------------------- ### listen() RPC Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-api.md Example of how to set up an RPC server to listen for incoming gossip connections. ```rust #[cfg(feature = "rpc")] { let gossip = Gossip::builder().spawn(endpoint); let (rpc_endpoint, _cert) = irpc::util::make_server_endpoint("127.0.0.1:9999".parse()?)?; tokio::spawn({ let api = gossip.deref().clone(); async move { api.listen(rpc_endpoint).await; } }); } ``` -------------------------------- ### alpn() Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Example of setting a custom ALPN protocol name. ```rust let gossip = Gossip::builder() .alpn(b"/my-gossip/1") .spawn(endpoint); // Use the same ALPN when registering with router Router::builder(endpoint) .accept(b"/my-gossip/1", gossip) .spawn(); ``` -------------------------------- ### Scope Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Example usage of Scope for broadcasts. ```rust // Swarm broadcast (via gossip tree) sender.broadcast(msg).await?; // Neighbor-only broadcast sender.broadcast_neighbors(msg).await?; ``` -------------------------------- ### max_message_size() Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Example of setting the maximum message size. ```rust let gossip = Gossip::builder() .max_message_size(8192) .spawn(endpoint); ``` -------------------------------- ### Hyparview Configuration Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Example of configuring Hyparview with custom capacities and shuffle interval. ```rust let mut config = HyparviewConfig::default(); config.active_view_capacity = 10; // More active connections config.passive_view_capacity = 50; // Larger passive set config.shuffle_interval = Duration::from_secs(30); // More frequent shuffles let gossip = Gossip::builder() .membership_config(config) .spawn(endpoint); ``` -------------------------------- ### Metrics Monitoring Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Example of accessing and monitoring gossip metrics. ```rust let metrics = gossip.metrics(); // Monitor message flow println!("Data sent: {}", metrics.msgs_data_sent); println!("Data recv: {}", metrics.msgs_data_recv); println!("Neighbors up: {}", metrics.neighbor_up); // Use in periodic monitoring task tokio::spawn({ let metrics = gossip.metrics().clone(); async move { loop { tokio::time::sleep(Duration::from_secs(10)).await; println!("Metrics: {:?}", metrics); } } }); ``` -------------------------------- ### Complete Example: Simple Chat Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md A basic chat application demonstrating how to set up an endpoint, spawn a gossip service, join a topic, and broadcast/receive messages. ```rust use std::io::{stdin, BufRead}; use bytes::Bytes; use iroh::{Endpoint, protocol::Router}; use iroh_gossip::{Gossip, TopicId, ALPN}; use n0_future::StreamExt; #[tokio::main] async fn main() -> anyhow::Result<()> { // Setup let endpoint = Endpoint::bind().await?; let gossip = Gossip::builder().spawn(endpoint.clone()); let router = Router::builder(endpoint) .accept(ALPN, gossip.clone()) .spawn(); // Join topic let topic_id = TopicId::from_bytes([0u8; 32]); let (sender, mut receiver) = gossip .subscribe_and_join(topic_id, vec![]) .await? .split(); println!("Connected! Type messages:"); // Spawn receiver task tokio::spawn(async move { while let Some(event) = receiver.next().await { if let Ok(iroh_gossip::api::Event::Received(msg)) = event { if let Ok(text) = std::str::from_utf8(&msg.content) { println!("< {}", text); } } } }); // Main loop: read stdin and broadcast let stdin = stdin(); let reader = stdin.lock(); for line in reader.lines() { if let Ok(text) = line { sender.broadcast(Bytes::from(text)).await?; } } router.shutdown().await?; Ok(()) } ``` -------------------------------- ### connect() RPC Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-api.md Example of how to create an RPC client to connect to a remote gossip instance. ```rust #[cfg(feature = "rpc")] { let client_endpoint = irpc::util::make_client_endpoint( "127.0.0.1:0".parse()?, &[&server_cert] )?; let rpc_client = GossipApi::connect(client_endpoint, server_addr); let topic = rpc_client.subscribe(topic_id, vec![]).await?; topic.broadcast(b"remote message".to_vec().into()).await?; } ``` -------------------------------- ### Plumtree Configuration Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Example of configuring Plumtree with custom timeouts and cache retention for a high-latency network. ```rust let mut config = PlumtreeConfig::default(); config.graft_timeout_1 = Duration::from_millis(100); // High-latency network config.message_cache_retention = Duration::from_secs(60); // Keep longer config.dispatch_timeout = Duration::from_millis(10); // Batching for efficiency let gossip = Gossip::builder() .broadcast_config(config) .spawn(endpoint); ``` -------------------------------- ### Multiplexing Multiple Topics Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Example of multiplexing multiple topics using tokio::select. ```rust let topic1 = gossip.subscribe(topic1_id, vec![]).await?; let topic2 = gossip.subscribe(topic2_id, vec![]).await?; // Handle both topics in same loop loop { tokio::select! { event1 = topic1.next() => { /* handle topic1 */ } event2 = topic2.next() => { /* handle topic2 */ } } } ``` -------------------------------- ### Message Serialization Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Example of serializing a custom message struct using serde. ```rust use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct MyMessage { text: String, timestamp: u64, } let msg = MyMessage { text: "Hello".to_string(), timestamp: now(), }; let serialized = serde_json::to_vec(&msg)?; topic.broadcast(serialized.into()).await?; ``` -------------------------------- ### Spawn Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md An example demonstrating how to spawn a gossip actor with a custom message size. ```rust #[tokio::main] async fn main() -> anyhow::Result<()> { let endpoint = Endpoint::bind().await?; let gossip = Gossip::builder() .max_message_size(8192) .spawn(endpoint); // gossip is now ready to use Ok(()) } ``` -------------------------------- ### Complete Configuration Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Demonstrates how to configure membership and broadcast protocols, and spawn a Gossip instance with custom settings. ```rust use iroh_gossip::{Gossip, proto::{HyparviewConfig, PlumtreeConfig}}; use std::time::Duration; #[tokio::main] async fn main() -> anyhow::Result<()> { let endpoint = Endpoint::bind().await?; // Configure membership protocol let mut membership = HyparviewConfig::default(); membership.active_view_capacity = 10; membership.passive_view_capacity = 50; membership.shuffle_interval = Duration::from_secs(30); // Configure broadcast protocol let mut broadcast = PlumtreeConfig::default(); broadcast.graft_timeout_1 = Duration::from_millis(100); broadcast.message_cache_retention = Duration::from_secs(60); // Create gossip with custom configuration let gossip = Gossip::builder() .max_message_size(8192) .membership_config(membership) .broadcast_config(broadcast) .spawn(endpoint.clone()); // Create router with custom ALPN (optional) let router = Router::builder(endpoint) .accept(iroh_gossip::ALPN, gossip.clone()) .spawn(); // Use gossip... Ok(()) } ``` -------------------------------- ### Message Deserialization on Receive Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Example of deserializing a received message using serde. ```rust while let Some(event) = receiver.next().await { if let Ok(Event::Received(msg)) = event { match serde_json::from_slice::(&msg.content) { Ok(my_msg) => { println!("Received: {}", my_msg.text); } Err(e) => { eprintln!("Failed to deserialize: {}", e); } } } } ``` -------------------------------- ### Metrics Access Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Example of accessing gossip metrics. ```rust let metrics = gossip.metrics(); println!("Data sent: {}", metrics.msgs_data_sent); println!("Neighbors up: {}", metrics.neighbor_up); ``` -------------------------------- ### Retry on Failure Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Example of publishing a message with retries on failure. ```rust async fn publish_with_retry( gossip: &Gossip, topic_id: TopicId, bootstrap: Vec, message: Bytes, ) -> Result<(), Box> { for attempt in 1..=3 { match gossip.subscribe(topic_id, bootstrap.clone()).await { Ok(mut topic) => { match topic.broadcast(message.clone()).await { Ok(()) => return Ok(()), Err(e) => { eprintln!("Attempt {} failed: {}", attempt, e); } } } Err(e) => { eprintln!("Attempt {} failed: {}", attempt, e); } } if attempt < 3 { tokio::time::sleep(Duration::from_millis(100 * attempt as u64)).await; } } Err("Failed after 3 attempts".into()) } ``` -------------------------------- ### Message struct example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Example of how to access fields of a received Message. ```rust if let Event::Received(msg) = event { println!("Message from {}: {:?}", msg.delivered_from, msg.content); if msg.scope.is_direct() { println!("Received directly from the sender"); } } ``` -------------------------------- ### DeliveryScope enum example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Example of how to match on the DeliveryScope of a message. ```rust match msg.scope { DeliveryScope::Swarm(round) => println!("Swarm message, {} hops away", round.0), DeliveryScope::Neighbors => println!("Direct from neighbor"), } ``` -------------------------------- ### Manual Testing Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Instructions for manually testing the chat application using the command line. ```bash # Terminal 1: Start first peer cargo run --example chat -- open # Terminal 2: Join using the ticket printed in Terminal 1 cargo run --example chat -- join # Type messages in either terminal to see them broadcast ``` -------------------------------- ### With Configuration Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Configuring the gossip protocol with custom membership and broadcast settings. ```rust use iroh_gossip::{Gossip, proto::{HyparviewConfig, PlumtreeConfig}}; use std::time::Duration; let endpoint = Endpoint::bind().await?; let mut membership = HyparviewConfig::default(); membership.active_view_capacity = 10; let mut broadcast = PlumtreeConfig::default(); broadcast.graft_timeout_1 = Duration::from_millis(100); let gossip = Gossip::builder() .max_message_size(8192) .membership_config(membership) .broadcast_config(broadcast) .spawn(endpoint); ``` -------------------------------- ### Example Cargo.toml Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Shows how to enable specific feature flags for the iroh-gossip dependency in Cargo.toml. ```toml [dependencies] iroh-gossip = { version = "0.95", features = ["net", "metrics"] } ``` -------------------------------- ### RPC Mode (Feature-gated) Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Example of using iroh-gossip in RPC mode, with feature gating. ```rust #[cfg(feature = "rpc")] { use irpc::util; // Server side let (rpc_endpoint, cert) = util::make_server_endpoint("127.0.0.1:9999".parse()?) let gossip_api = gossip.deref().clone(); tokio::spawn(async move { gossip_api.listen(rpc_endpoint).await; }); // Client side let client_endpoint = util::make_client_endpoint("127.0.0.1:0".parse()?, &[&cert])?; let rpc_client = GossipApi::connect(client_endpoint, server_addr); let topic = rpc_client.subscribe(topic_id, vec![]).await?; } ``` -------------------------------- ### Filtering Events Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Example of filtering events to only handle received messages. ```rust use n0_future::StreamExt; while let Some(event) = receiver.next().await { // Only handle Received events if let Ok(Event::Received(msg)) = event { handle_message(msg).await; } } ``` -------------------------------- ### joined() Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-receiver.md Waits until at least one peer connects to the topic. ```rust let (sender, mut receiver) = topic.split(); // Blocks until at least one peer is up receiver.joined().await?; println!("Now connected to swarm!"); // Use neighbors() or start consuming events while let Some(event) = receiver.next().await { // handle event } ``` -------------------------------- ### Event enum usage example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Example of how to process events from a GossipReceiver stream. ```rust while let Some(event) = receiver.next().await { match event? { Event::NeighborUp(peer) => println!("Peer {} joined", peer), Event::NeighborDown(peer) => println!("Peer {} left", peer), Event::Received(msg) => println!("Got message: {:?}", msg.content), Event::Lagged => eprintln!("Fell behind!"), } } ``` -------------------------------- ### join_peers() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-sender.md Attempts to join and connect to a set of peers for this topic. ```rust let new_peers = vec![peer_a, peer_b]; sender.join_peers(new_peers).await?; ``` -------------------------------- ### Simple Subscription Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Subscribing to a topic with a given TopicId and optional bootstrap peers. ```rust use iroh_gossip::TopicId; let topic_id = TopicId::from_bytes([0u8; 32]); let bootstrap_peers = vec![]; // or list of peer EndpointIds let mut topic = gossip.subscribe(topic_id, bootstrap_peers).await?; // topic is ready to use, but may not be connected yet ``` -------------------------------- ### Wait for First Connection Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Block until at least one neighbor connects. ```rust // Block until at least one neighbor connects receiver.joined().await?; // Now we have at least one neighbor for peer in receiver.neighbors() { println!("Connected to: {}", peer); } ``` -------------------------------- ### Broadcast to All Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Broadcasting a message to all peers subscribed to the topic. ```rust let message = b"Hello, swarm!".to_vec(); topic.broadcast(message.into()).await?; ``` -------------------------------- ### Stream Implementation Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-receiver.md Demonstrates consuming events from the GossipReceiver stream. ```rust use n0_future::{Stream, StreamExt}; let (sender, mut receiver) = topic.split(); while let Some(result) = receiver.next().await { match result { Ok(event) => match event { Event::Received(msg) => { println!("Message from {}: {:?}", msg.delivered_from, msg.content); } Event::NeighborUp(peer) => { println!("Peer joined: {}", peer); } Event::NeighborDown(peer) => { println!("Peer left: {}", peer); } Event::Lagged => { println!("Receiver fell behind, some messages were dropped"); } } Err(e) => { println!("Topic error: {}", e); break; } } } ``` -------------------------------- ### broadcast() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-sender.md Broadcasts a message to all peers in the swarm. ```rust use bytes::Bytes; let (_sender, _receiver) = topic.split(); let msg = Bytes::from("Hello, swarm!"); sender.broadcast(msg).await?; ``` -------------------------------- ### Using the Simulator (requires `test-utils` feature) Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md A test function demonstrating how to use the gossip simulator to test network behavior. ```rust #[cfg(feature = "test-utils")] #[test] fn test_gossip() { use iroh_gossip::proto::sim::{Network, NetworkConfig}; use iroh_gossip::proto::{Config, Command, Event}; use rand_chacha::ChaCha12Rng; use rand::SeedableRng; let config = Config::default(); let mut network = Network::new(config.into(), ChaCha12Rng::seed_from_u64(42)); // Add nodes network.insert(0); network.insert(1); network.insert(2); let topic_id = [0u8; 32].into(); // Commands network.command(0, topic_id, Command::Join(vec![])); network.command(1, topic_id, Command::Join(vec![0])); // Run protocol network.run_trips(3); // Check events let events = network.events(); // Assertions... } ``` -------------------------------- ### split() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-topic.md Splits this topic into separate sender and receiver handles. ```rust let (sender, mut receiver) = topic.split(); // Spawn a receiver task tokio::spawn(async move { while let Some(event) = receiver.next().await { match event? { Event::Received(msg) => println!("Got: {:?}", msg.content), Event::NeighborUp(peer) => println!("Peer up: {}", peer), _ => {} } } }); // Use sender in main task sender.broadcast(b"hello".to_vec().into()).await?; ``` -------------------------------- ### broadcast() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-topic.md Broadcasts a message to all peers in the swarm for this topic. ```rust let mut topic = gossip.subscribe(topic_id, bootstrap).await?; topic.joined().await?; // Wait for at least one peer let msg = "Hello, gossip swarm!".as_bytes().to_vec().into(); topic.broadcast(msg).await?; ``` -------------------------------- ### joined() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-topic.md Waits until the node is connected to at least one peer in the topic. ```rust let mut topic = gossip.subscribe(topic_id, bootstrap).await?; // Blocks until at least one neighbor is up topic.joined().await?; println!("Connected to swarm!"); // Safe to broadcast now topic.broadcast(b"message".to_vec().into()).await?; ``` -------------------------------- ### Check Connection Status Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Check if connected to the swarm. ```rust if receiver.is_joined() { println!("Connected to swarm"); } else { println!("Waiting for first peer"); } ``` -------------------------------- ### Minimal Configuration Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md Example of creating a Gossip instance with minimal configuration, using all defaults. ```rust let gossip = Gossip::builder().spawn(endpoint); ``` -------------------------------- ### Handle Backpressure Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Handle backpressure when the receiver falls behind. ```rust while let Some(result) = receiver.next().await { match result { Ok(Event::Lagged) => { eprintln!("Receiver fell behind!"); // Options: // 1. Close and reconnect with larger capacity break; // 2. Pause publishing to let queue drain // 3. Speed up message processing } Ok(event) => { /* handle event */ } Err(e) => { eprintln!("Error: {}", e); break; } } } ``` -------------------------------- ### Graceful Shutdown Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Handle graceful shutdown of the gossip service. ```rust match gossip.shutdown().await { Ok(()) => println!("Shut down successfully"), Err(net::Error::ActorDropped) => { println!("Already dropped"); } } ``` -------------------------------- ### Neighbor Tracking Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-receiver.md Shows how to track neighbor state changes using events. ```rust let (sender, mut receiver) = topic.split(); // Subscribe and spawn a listener let listener = tokio::spawn(async move { while let Some(event) = receiver.next().await { match event { Ok(Event::NeighborUp(peer)) => { println!("Peer up: {}", peer); } Ok(Event::NeighborDown(peer)) => { println!("Peer down: {}", peer); } _ => {} } } }); // Call neighbors() at any time to see current neighbors println!("Current neighbors: {:?}", receiver.neighbors().collect::>()); ``` -------------------------------- ### Handle Connection Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip.md Handles an incoming connection from a peer. Should be called after checking the ALPN protocol is `GOSSIP_ALPN`. ```rust use iroh::protocol::Router; use iroh_gossip::ALPN; async fn handle_incoming(router: Router, gossip: Gossip) { let endpoint = router.endpoint(); // In a real application, this would be part of your connection handling loop // when receiving connections with ALPN matching GOSSIP_ALPN } ``` -------------------------------- ### Metrics Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip.md Returns a reference to the metrics tracked for this gossip instance. ```rust let metrics = gossip.metrics(); // Access specific metrics via metrics.msgs_data_sent, metrics.neighbor_up, etc. ``` -------------------------------- ### Subscription with Connection Guarantee Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Subscribing to a topic and waiting until at least one peer connection is established before proceeding. ```rust // Wait for at least one peer connection let mut topic = gossip.subscribe_and_join(topic_id, bootstrap_peers).await?; // Now safe to broadcast topic.broadcast(b"hello".to_vec().into()).await?; ``` -------------------------------- ### Large Swarm Configuration Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md Example demonstrating configuration for a large swarm, adjusting membership and broadcast settings. ```rust let mut membership = HyparviewConfig::default(); membership.active_view_capacity = 30; membership.passive_view_capacity = 150; let mut broadcast = PlumtreeConfig::default(); broadcast.graft_timeout_1 = Duration::from_millis(150); broadcast.message_cache_retention = Duration::from_secs(120); let gossip = Gossip::builder() .max_message_size(16384) .membership_config(membership) .broadcast_config(broadcast) .spawn(endpoint); ``` -------------------------------- ### Gossip Constructor Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip.md Creates a default `Builder` for configuring and spawning a `Gossip` instance. ```rust use iroh::{Endpoint, protocol::Router}; use iroh_gossip::Gossip; #[tokio::main] async fn main() -> anyhow::Result<()> { let endpoint = Endpoint::bind().await?; let gossip = Gossip::builder().spawn(endpoint.clone()); let router = Router::builder(endpoint) .accept(iroh_gossip::ALPN, gossip.clone()) .spawn(); router.shutdown().await?; Ok(()) } ``` -------------------------------- ### Subscription with Custom Capacity Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Subscribing to a topic with custom join options, including increasing the subscription buffer capacity. ```rust use iroh_gossip::api::JoinOptions; let mut opts = JoinOptions::with_bootstrap(bootstrap_peers); opts.subscription_capacity = 4096; // Increase buffer for slow subscribers let topic = gossip.subscribe_with_opts(topic_id, opts).await?; ``` -------------------------------- ### neighbors() Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-receiver.md Iterates over the current direct neighbors in the swarm. ```rust let (sender, mut receiver) = topic.split(); for peer_id in receiver.neighbors() { println!("Connected to: {}", peer_id); } ``` -------------------------------- ### Publishing Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/README.md Code examples for publishing messages using GossipSender. ```rust GossipTopic / GossipSender .broadcast(Bytes) -> Result<(), ApiError> .broadcast_neighbors(Bytes) -> Result<(), ApiError> .join_peers(Vec) -> Result<(), ApiError> ``` -------------------------------- ### Simple broadcast with 3 peers (A, B, C) Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/protocol-overview.md Message flow example for a simple broadcast scenario involving three peers. ```text 1. A broadcasts message "hello" A → B (eager, full message) A → C (lazy, message ID only) 2. C receives IHave from A, waits timeout 3. B receives message from A, forwards B → C (eager, full message) ← arrives before timeout 4. C receives full message from B before timeout expires Message delivered to application 5. If network slow, C's timeout expires: C → A (Graft: "send full message") A → C (responds with full message) C is now eager with A ``` -------------------------------- ### Recovering from Topic Closure Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/errors.md An example demonstrating how to recover from topic closure by retrying subscription and broadcast operations. ```rust use iroh_gossip::api::ApiError; async fn publish_with_retry( gossip: &Gossip, topic_id: TopicId, bootstrap: Vec, message: Bytes, ) -> Result<(), Box> { loop { match gossip.subscribe(topic_id, bootstrap.clone()).await { Ok(mut topic) => { match topic.broadcast(message.clone()).await { Ok(()) => return Ok(()), Err(ApiError::Closed) => { eprintln!("Topic closed, reconnecting..."); continue; // Retry } Err(e) => return Err(Box::new(e)), } } Err(e) => return Err(Box::new(e)), } } } ``` -------------------------------- ### ApiError::Rpc Catch Pattern Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/errors.md Example of how to catch and handle ApiError::Rpc. ```rust match result { Err(ApiError::Rpc { source }) => { eprintln!("RPC error: {}", source); // Retry or fallback } // ... } ``` -------------------------------- ### Simple Event Loop Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md A basic event loop for receiving messages and peer status updates from a gossip topic. ```rust use n0_future::StreamExt; let (sender, mut receiver) = topic.split(); while let Some(event) = receiver.next().await { match event? { Event::Received(msg) => { println!("Got: {:?}", msg.content); println!("From: {}", msg.delivered_from); } Event::NeighborUp(peer) => println!("Peer up: {}", peer), Event::NeighborDown(peer) => println!("Peer down: {}", peer), Event::Lagged => eprintln!("Fell behind!"), } } ``` -------------------------------- ### Multiple Gossip Instances with Different ALPNs Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md Example showing how to spawn multiple gossip instances with distinct ALPNs and register them with a router. ```rust let endpoint = Endpoint::bind().await?; let gossip1 = Gossip::builder() .alpn(b"/gossip-app-1/1") .spawn(endpoint.clone()); let gossip2 = Gossip::builder() .alpn(b"/gossip-app-2/1") .spawn(endpoint.clone()); let router = Router::builder(endpoint) .accept(b"/gossip-app-1/1", gossip1) .accept(b"/gossip-app-2/1", gossip2) .spawn(); ``` -------------------------------- ### Creating & Managing Gossip Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/README.md Code examples for creating and managing gossip instances, including builder methods and API calls. ```rust Gossip::builder() .max_message_size(usize) -> Builder .membership_config(HyparviewConfig) -> Builder .broadcast_config(PlumtreeConfig) -> Builder .alpn(impl AsRef<[u8]>) -> Builder .spawn(Endpoint) -> Gossip Gossip .deref() -> &GossipApi .subscribe(TopicId, Vec) -> GossipTopic .subscribe_and_join(TopicId, Vec) -> GossipTopic .subscribe_with_opts(TopicId, JoinOptions) -> GossipTopic .max_message_size() -> usize .metrics() -> &Arc .handle_connection(Connection) -> Result<(), Error> .shutdown() -> Result<(), Error> ``` -------------------------------- ### Graceful Shutdown Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/errors.md An example of how to gracefully shut down the gossip service, handling the case where the actor might have already been dropped. ```rust async fn shutdown_gossip(gossip: Gossip) -> Result<(), Box> { match gossip.shutdown().await { Ok(()) => { println!("Gossip shut down gracefully"); Ok(()) } Err(Error::ActorDropped) => { // Actor was already dropped, nothing to do println!("Actor was already dropped"); Ok(()) } } } ``` -------------------------------- ### High-Latency Network Configuration Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md Example configuring gossip for a high-latency network by adjusting shuffle intervals and timeouts. ```rust let mut membership = HyparviewConfig::default(); membership.shuffle_interval = Duration::from_secs(120); // Less frequent membership.neighbor_request_timeout = Duration::from_secs(2); // Longer timeout let mut broadcast = PlumtreeConfig::default(); broadcast.graft_timeout_1 = Duration::from_millis(500); // Much longer broadcast.graft_timeout_2 = Duration::from_millis(250); broadcast.message_cache_retention = Duration::from_secs(180); // 3 minutes let gossip = Gossip::builder() .membership_config(membership) .broadcast_config(broadcast) .spawn(endpoint); ``` -------------------------------- ### Pattern Matching on Events Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Detailed pattern matching on various gossip events, including message delivery scope and peer status changes. ```rust use iroh_gossip::api::{Event, Message}; while let Some(result) = receiver.next().await { match result { Ok(Event::Received(msg)) => { // Check delivery scope match msg.scope { DeliveryScope::Swarm(round) => { println!("Gossip message {} hops away", round.0); } DeliveryScope::Neighbors => { println!("Direct from publisher"); } } } Ok(Event::NeighborUp(peer)) => { println!("Peer joined: {}", peer); } Ok(Event::NeighborDown(peer)) => { println!("Peer left: {}", peer); } Ok(Event::Lagged) => { eprintln!("Receiver fell behind, restarting"); break; // Reconnect } Err(e) => { eprintln!("Error: {}", e); break; } } } ``` -------------------------------- ### Broadcast from Sender Half Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Splitting a topic into sender and receiver halves, and broadcasting a message from the sender half in a separate task. ```rust let (sender, mut receiver) = topic.split(); tokio::spawn(async move { sender.broadcast(message.into()).await?; Ok::<_, Box>(()) }); ``` -------------------------------- ### Shutdown Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip.md Gracefully shuts down the gossip instance. Leaves all topics, sends disconnect messages to peers, and stops the gossip actor. ```rust let gossip = Gossip::builder().spawn(endpoint.clone()); // ... use gossip ... gossip.shutdown().await?; println!("Gossip instance shut down"); ``` -------------------------------- ### Error Propagation with `?` Operator Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/errors.md An example showing how to use the `?` operator for concise error propagation, as all error types implement `std::error::Error`. ```rust async fn example(gossip: &Gossip, topic_id: TopicId) -> Result<(), Box> { let mut topic = gossip.subscribe(topic_id, vec![]).await?; topic.joined().await?; topic.broadcast(b"hello".to_vec().into()).await?; Ok(()) } ``` -------------------------------- ### Set up gossip with custom configuration Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/README.md Demonstrates how to initialize the Gossip system with custom configurations for message size, membership, and broadcasting. ```rust let gossip = Gossip::builder() .max_message_size(8192) .membership_config(custom_membership_config) .broadcast_config(custom_broadcast_config) .spawn(endpoint); ``` -------------------------------- ### broadcast_neighbors() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-topic.md Broadcasts a message only to direct neighbors, not the entire swarm. ```rust topic.broadcast_neighbors(b"neighbor-only message".to_vec().into()).await?; ``` -------------------------------- ### is_joined() Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-receiver.md Returns true if currently connected to at least one peer. ```rust if receiver.is_joined() { println!("Connected!"); } else { println!("Waiting for first peer..."); } ``` -------------------------------- ### broadcast_neighbors() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-sender.md Broadcasts a message only to direct neighbors (active view peers). ```rust sender.broadcast_neighbors(Bytes::from("direct message")).await?; ``` -------------------------------- ### Error::ActorDropped Catch Pattern Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/errors.md Example of how to catch and handle Error::ActorDropped. ```rust match gossip.shutdown().await { Ok(()) => println!("Gracefully shut down"), Err(Error::ActorDropped) => { // Actor already stopped, safe to continue println!("Actor was already dropped"); } } ``` -------------------------------- ### ApiError::Closed Catch Pattern Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/errors.md Example of how to catch and handle ApiError::Closed. ```rust match result { Err(ApiError::Closed) => { eprintln!("Topic closed"); // Reconnect or return error to user } // ... } ``` -------------------------------- ### Create endpoint and gossip Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/README.md Create a network endpoint and initialize the gossip service. ```rust let endpoint = Endpoint::bind().await?; let gossip = Gossip::builder().spawn(endpoint.clone()); ``` -------------------------------- ### neighbors() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-topic.md Returns an iterator over the current direct neighbors in the swarm membership layer. ```rust for peer_id in topic.neighbors() { println!("Connected to peer: {}", peer_id); } ``` -------------------------------- ### is_joined() example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-topic.md Returns true if the node is currently connected to at least one peer in the topic. ```rust if topic.is_joined() { topic.broadcast(msg).await?; } else { println!("Not connected yet"); } ``` -------------------------------- ### Receiving Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/README.md Code examples for receiving messages and managing subscriptions using GossipReceiver. ```rust GossipTopic / GossipReceiver .split() -> (GossipSender, GossipReceiver) .joined() -> Result<(), ApiError> .is_joined() -> bool .neighbors() -> impl Iterator impl Stream> for GossipReceiver impl Stream> for GossipTopic ``` -------------------------------- ### Check Message Size Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Checking if a message exceeds the maximum allowed size before broadcasting. ```rust let max_size = gossip.max_message_size(); if message.len() > max_size { eprintln!("Message too large"); } else { topic.broadcast(message.into()).await?; } ``` -------------------------------- ### Broadcast to Neighbors Only Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/examples.md Broadcasting a message only to direct neighbors, without propagating it through the gossip tree. ```rust // Only send to direct neighbors, don't propagate via gossip tree topic.broadcast_neighbors(message.into()).await?; ``` -------------------------------- ### Connection Model Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/protocol-overview.md Diagram illustrating the Iroh Endpoint's connection model, showing how it handles networking and connects to Gossip Handlers via ALPN. ```text ┌─────────────────────────────────────────┐ │ Iroh Endpoint │ │ (handles all networking, NAT, relays) │ └──────────────┬──────────────────────────┘ │ ├─ ALPN: /iroh-gossip/1 ──→ Gossip Handler │ └─ ALPN: other ─────────→ Other Handlers ``` -------------------------------- ### Custom Message Size Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md Example of configuring a custom maximum message size for the gossip instance. ```rust let gossip = Gossip::builder() .max_message_size(16384) .spawn(endpoint); ``` -------------------------------- ### membership_config() Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md Configures the swarm membership protocol (HyParView). ```rust pub fn membership_config(mut self, config: HyparviewConfig) -> Self ``` ```rust let mut config = HyparviewConfig::default(); config.active_view_capacity = 10; // More active connections config.passive_view_capacity = 50; // Remember more peers config.shuffle_interval = Duration::from_secs(30); // More frequent shuffles Gossip::builder() .membership_config(config) .spawn(endpoint) ``` -------------------------------- ### Gossip::builder() Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/builder.md Creates a Builder with default configuration. ```rust pub fn builder() -> Builder ``` ```rust let builder = Gossip::builder(); let gossip = builder.spawn(endpoint); ``` -------------------------------- ### Max Message Size Example Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip.md Returns the maximum message size (in bytes) configured for this gossip instance. ```rust let max_size = gossip.max_message_size(); println!("Max message size: {} bytes", max_size); ``` -------------------------------- ### HyParViewConfig struct Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/configuration.md Membership protocol settings. ```rust pub struct HyparviewConfig { pub active_view_capacity: usize, pub passive_view_capacity: usize, pub active_random_walk_length: Ttl, pub passive_random_walk_length: Ttl, pub shuffle_random_walk_length: Ttl, pub shuffle_active_view_count: usize, pub shuffle_passive_view_count: usize, pub shuffle_interval: Duration, pub neighbor_request_timeout: Duration, } ``` -------------------------------- ### JoinOptions Struct Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/types.md Options for joining a gossip topic. ```rust pub struct JoinOptions { /// Initial bootstrap endpoints pub bootstrap: BTreeSet, /// Maximum number of messages buffered in subscription pub subscription_capacity: usize, } ``` -------------------------------- ### subscribe_and_join() Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-api.md Joins a gossip topic and waits for at least one active connection to be established. This is a convenience method that combines subscribe_with_opts() and joined(). It ensures the topic is connected before returning. ```rust pub async fn subscribe_and_join( &self, topic_id: TopicId, bootstrap: Vec, ) -> Result ``` ```rust // Guaranteed to have at least one neighbor after this call let mut topic = gossip.subscribe_and_join(topic_id, bootstrap_peers).await?; topic.broadcast(b"hello".to_vec().into()).await?; ``` -------------------------------- ### Subscribe to a topic Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/README.md Subscribe to a topic and join the swarm, optionally providing bootstrap peers. ```rust let mut topic = gossip.subscribe_and_join(topic_id, bootstrap_peers).await?; ``` -------------------------------- ### subscribe() Source: https://github.com/p2panda/iroh-gossip/blob/main/_autodocs/gossip-api.md Joins a gossip topic with the default options. Returns immediately; does not wait for connections. Messages will queue until at least one connection is available. To ensure connectivity, call GossipTopic::joined() after subscribing. ```rust pub async fn subscribe( &self, topic_id: TopicId, bootstrap: Vec, ) -> Result ``` ```rust use iroh_gossip::{Gossip, api::TopicId}; use iroh::EndpointId; let gossip = Gossip::builder().spawn(endpoint); let topic_id = TopicId::from_bytes([0u8; 32]); let bootstrap_peers = vec![/* list of peer EndpointIds */]; let mut topic = gossip.subscribe(topic_id, bootstrap_peers).await?; // Wait for at least one connection before publishing topic.joined().await?; // Now safe to broadcast topic.broadcast(b"hello".to_vec().into()).await?; ```