use async_std::io;
use futures::{prelude::*, select};
use libp2p::gossipsub::MessageId;
use libp2p::gossipsub::{
Gossipsub, GossipsubEvent, GossipsubMessage, IdentTopic as Topic, MessageAuthenticity,
ValidationMode,
};
use libp2p::{
gossipsub, identity, mdns, swarm::NetworkBehaviour, swarm::SwarmEvent, PeerId, Swarm,
};
use std::collections::hash_map::DefaultHasher;
use std::error::Error;
use std::hash::{Hash, Hasher};
use std::time::Duration;
#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
println!("Local peer id: {local_peer_id}");
let transport = libp2p::development_transport(local_key.clone()).await?;
#[derive(NetworkBehaviour)]
struct MyBehaviour {
gossipsub: Gossipsub,
mdns: mdns::async_io::Behaviour,
}
let message_id_fn = |message: &GossipsubMessage| {
let mut s = DefaultHasher::new();
message.data.hash(&mut s);
MessageId::from(s.finish().to_string())
};
let gossipsub_config = gossipsub::GossipsubConfigBuilder::default()
.heartbeat_interval(Duration::from_secs(10)) .validation_mode(ValidationMode::Strict) .message_id_fn(message_id_fn) .build()
.expect("Valid config");
let mut gossipsub = Gossipsub::new(MessageAuthenticity::Signed(local_key), gossipsub_config)
.expect("Correct configuration");
let topic = Topic::new("test-net");
gossipsub.subscribe(&topic)?;
let mut swarm = {
let mdns = mdns::async_io::Behaviour::new(mdns::Config::default())?;
let behaviour = MyBehaviour { gossipsub, mdns };
Swarm::with_async_std_executor(transport, behaviour, local_peer_id)
};
let mut stdin = io::BufReader::new(io::stdin()).lines().fuse();
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
println!("Enter messages via STDIN and they will be sent to connected peers using Gossipsub");
loop {
select! {
line = stdin.select_next_some() => {
if let Err(e) = swarm
.behaviour_mut().gossipsub
.publish(topic.clone(), line.expect("Stdin not to close").as_bytes()) {
println!("Publish error: {e:?}");
}
},
event = swarm.select_next_some() => match event {
SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => {
for (peer_id, _multiaddr) in list {
println!("mDNS discovered a new peer: {peer_id}");
swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer_id);
}
},
SwarmEvent::Behaviour(MyBehaviourEvent::Mdns(mdns::Event::Expired(list))) => {
for (peer_id, _multiaddr) in list {
println!("mDNS discover peer has expired: {peer_id}");
swarm.behaviour_mut().gossipsub.remove_explicit_peer(&peer_id);
}
},
SwarmEvent::Behaviour(MyBehaviourEvent::Gossipsub(GossipsubEvent::Message {
propagation_source: peer_id,
message_id: id,
message,
})) => println!(
"Got message: '{}' with id: {id} from peer: {peer_id}",
String::from_utf8_lossy(&message.data),
),
_ => {}
}
}
}
}