use ipfrs_network::{GossipSubConfig, GossipSubManager, GossipSubMessage, MessageId, TopicId};
use libp2p::PeerId;
use std::time::{Duration, Instant};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== IPFRS GossipSub Example ===\n");
println!("1. Creating GossipSub manager...");
let config = GossipSubConfig {
mesh_n_low: 4,
mesh_n: 6,
mesh_n_high: 12,
gossip_n: 3,
heartbeat_interval: Duration::from_secs(1),
max_message_size: 1024 * 1024, enable_scoring: true,
duplicate_cache_time: Duration::from_secs(120),
max_duplicate_cache_size: 10000,
enable_validation: true,
};
let manager = GossipSubManager::new(config);
println!(" ✓ GossipSub manager created\n");
println!("2. Subscribing to topics...");
manager.subscribe(TopicId::content_announce())?;
println!(" ✓ Subscribed to: {}", TopicId::content_announce().0);
manager.subscribe(TopicId::peer_announce())?;
println!(" ✓ Subscribed to: {}", TopicId::peer_announce().0);
manager.subscribe(TopicId::dht_events())?;
println!(" ✓ Subscribed to: {}", TopicId::dht_events().0);
let custom_topic = TopicId::new("/myapp/chat/general");
manager.subscribe(custom_topic.clone())?;
println!(" ✓ Subscribed to: {}\n", custom_topic.0);
println!("3. Building topic mesh...");
let peers = vec![
PeerId::random(),
PeerId::random(),
PeerId::random(),
PeerId::random(),
PeerId::random(),
PeerId::random(),
];
for peer in &peers {
manager.add_peer_to_mesh(&TopicId::content_announce(), *peer)?;
}
println!(" ✓ Added {} peers to mesh", peers.len());
let mesh_peers = manager.get_mesh_peers(&TopicId::content_announce())?;
println!(" Current mesh size: {}\n", mesh_peers.len());
println!("4. Publishing messages...");
let source_peer = PeerId::random();
let content_announcement = b"New content available: QmXYZ123...";
let msg_id = manager.publish(
TopicId::content_announce(),
content_announcement.to_vec(),
source_peer,
)?;
println!(" ✓ Published content announcement");
println!(" Message ID: {:?}", &msg_id.0[..8]);
let peer_announcement = b"New peer joined: 12D3KooWABC...";
let msg_id = manager.publish(
TopicId::peer_announce(),
peer_announcement.to_vec(),
source_peer,
)?;
println!(" ✓ Published peer announcement");
println!(" Message ID: {:?}\n", &msg_id.0[..8]);
println!("5. Handling incoming messages...");
let messages = [
GossipSubMessage {
id: MessageId::new(&peers[0], 1),
source: peers[0],
topic: TopicId::content_announce(),
data: b"Content from peer 1".to_vec(),
sequence: 1,
timestamp: Instant::now(),
},
GossipSubMessage {
id: MessageId::new(&peers[1], 1),
source: peers[1],
topic: TopicId::content_announce(),
data: b"Content from peer 2".to_vec(),
sequence: 1,
timestamp: Instant::now(),
},
GossipSubMessage {
id: MessageId::new(&peers[0], 1),
source: peers[0],
topic: TopicId::content_announce(),
data: b"Content from peer 1".to_vec(),
sequence: 1,
timestamp: Instant::now(),
},
];
for (i, msg) in messages.iter().enumerate() {
let is_new = manager.handle_message(msg.clone())?;
if is_new {
println!(" ✓ Message {}: NEW (from {})", i + 1, msg.source);
} else {
println!(" ⊗ Message {}: DUPLICATE (filtered)", i + 1);
}
}
println!();
println!("6. Managing peer scores...");
manager.update_peer_score(&peers[0], TopicId::content_announce(), 0.9);
manager.update_peer_score(&peers[1], TopicId::content_announce(), 0.7);
manager.update_peer_score(&peers[2], TopicId::content_announce(), 0.3); manager.update_peer_score(&peers[3], TopicId::content_announce(), 0.4);
println!(" Peer scores:");
for peer in &peers[..4] {
if let Some(score) = manager.get_peer_score(peer) {
println!(" - {}: {:.2}", peer, score.total_score);
}
}
println!();
let threshold = 0.5;
let peers_to_prune = manager.get_peers_to_prune(&TopicId::content_announce(), threshold);
println!(" Peers below threshold ({:.1}):", threshold);
for peer in &peers_to_prune {
println!(" - {} (should be pruned)", peer);
}
println!();
for peer in peers_to_prune {
manager.remove_peer_from_mesh(&TopicId::content_announce(), &peer)?;
println!(" ✗ Removed {} from mesh", peer);
}
println!();
println!("7. GossipSub Statistics:");
let stats = manager.stats();
println!(" Subscribed topics: {}", stats.subscribed_topics);
println!(" Messages published: {}", stats.messages_published);
println!(" Messages received: {}", stats.messages_received);
println!(" Duplicate messages: {}", stats.duplicate_messages);
println!(" Invalid messages: {}", stats.invalid_messages);
println!(" Active mesh peers: {}", stats.active_mesh_peers);
println!(" Mesh graft events: {}", stats.mesh_graft_count);
println!(" Mesh prune events: {}", stats.mesh_prune_count);
println!("\n Messages per topic:");
for (topic, count) in &stats.messages_per_topic {
println!(" - {}: {}", topic, count);
}
println!();
println!("8. Subscribed topics:");
let topics = manager.list_topics();
for topic in topics {
let _is_subscribed = manager.is_subscribed(&topic);
let peers = manager.get_mesh_peers(&topic).unwrap_or_default();
println!(" - {} ({} peers)", topic.0, peers.len());
}
println!("\n=== Example Complete ===");
Ok(())
}
#[allow(dead_code)]
fn content_announcement_workflow() -> Result<(), Box<dyn std::error::Error>> {
let manager = GossipSubManager::new(GossipSubConfig::default());
manager.subscribe(TopicId::content_announce())?;
let cid = "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco";
let announcement = format!(
r#"{{"type":"content_available","cid":"{}","provider":"12D3KooW..."}}"#,
cid
);
let source = PeerId::random();
manager.publish(
TopicId::content_announce(),
announcement.as_bytes().to_vec(),
source,
)?;
println!("Content announced to network");
Ok(())
}
#[allow(dead_code)]
fn chat_application_example() -> Result<(), Box<dyn std::error::Error>> {
let manager = GossipSubManager::new(GossipSubConfig::default());
let rooms = vec!["general", "dev", "random"];
for room in rooms {
let topic = TopicId::new(format!("/chat/{}", room));
manager.subscribe(topic.clone())?;
println!("Joined room: {}", room);
}
let room_topic = TopicId::new("/chat/general");
let message = r#"{"user":"alice","text":"Hello everyone!"}"#;
let source = PeerId::random();
manager.publish(room_topic, message.as_bytes().to_vec(), source)?;
println!("Message sent to general room");
Ok(())
}
#[allow(dead_code)]
fn event_streaming_example() -> Result<(), Box<dyn std::error::Error>> {
let manager = GossipSubManager::new(GossipSubConfig::default());
manager.subscribe(TopicId::dht_events())?;
let events = vec![
r#"{"event":"peer_discovered","peer":"12D3KooWABC..."}"#,
r#"{"event":"provider_found","cid":"QmXYZ...","peer":"12D3KooWDEF..."}"#,
r#"{"event":"routing_table_updated","buckets":15,"peers":234}"#,
];
let source = PeerId::random();
for event in &events {
manager.publish(TopicId::dht_events(), event.as_bytes().to_vec(), source)?;
}
println!("Published {} DHT events", events.len());
Ok(())
}
#[allow(dead_code)]
fn message_validation_example() -> Result<(), Box<dyn std::error::Error>> {
let config = GossipSubConfig {
enable_validation: true,
max_message_size: 1024, ..Default::default()
};
let manager = GossipSubManager::new(config);
let topic = TopicId::new("/validated/topic");
manager.subscribe(topic.clone())?;
let large_message = vec![0u8; 2048]; let source = PeerId::random();
match manager.publish(topic, large_message, source) {
Ok(_) => println!("Message published"),
Err(e) => println!("Message rejected: {}", e),
}
Ok(())
}
#[allow(dead_code)]
fn mesh_optimization_example() -> Result<(), Box<dyn std::error::Error>> {
let config = GossipSubConfig {
mesh_n_low: 4,
mesh_n: 6,
mesh_n_high: 12,
enable_scoring: true,
..Default::default()
};
let manager = GossipSubManager::new(config);
let topic = TopicId::new("/optimized/topic");
manager.subscribe(topic.clone())?;
let peers: Vec<_> = (0..15).map(|_| PeerId::random()).collect();
for peer in &peers {
manager.add_peer_to_mesh(&topic, *peer)?;
}
let mesh_size = manager.get_mesh_peers(&topic)?.len();
println!("Mesh size: {} (target: 6, max: 12)", mesh_size);
for (i, peer) in peers.iter().enumerate() {
let score = 0.5 + (i as f64 / peers.len() as f64) * 0.5;
manager.update_peer_score(peer, topic.clone(), score);
}
let to_prune = manager.get_peers_to_prune(&topic, 0.6);
println!("Peers to prune: {}", to_prune.len());
for peer in to_prune {
manager.remove_peer_from_mesh(&topic, &peer)?;
}
let final_mesh_size = manager.get_mesh_peers(&topic)?.len();
println!("Final mesh size: {}", final_mesh_size);
Ok(())
}