// Copyright 2021 COMIT Network. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. use futures::StreamExt; use libp2p::core::identity; use libp2p::core::PeerId; use libp2p::multiaddr::Protocol; use libp2p::ping::{Ping, PingConfig, PingEvent, PingSuccess}; use libp2p::swarm::SwarmEvent; use libp2p::Swarm; use libp2p::{development_transport, rendezvous, Multiaddr}; use std::time::Duration; const NAMESPACE: &str = "rendezvous"; #[tokio::main] async fn main() { env_logger::init(); let identity = identity::Keypair::generate_ed25519(); let rendezvous_point_address = "/ip4/127.0.0.1/tcp/62649".parse::().unwrap(); let rendezvous_point = "12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN" .parse() .unwrap(); let mut swarm = Swarm::new( development_transport(identity.clone()).await.unwrap(), MyBehaviour { rendezvous: rendezvous::client::Behaviour::new(identity.clone()), ping: Ping::new( PingConfig::new() .with_interval(Duration::from_secs(1)) .with_keep_alive(true), ), }, PeerId::from(identity.public()), ); log::info!("Local peer id: {}", swarm.local_peer_id()); let _ = swarm.dial(rendezvous_point_address.clone()).unwrap(); let mut discover_tick = tokio::time::interval(Duration::from_secs(30)); let mut cookie = None; loop { tokio::select! { event = swarm.select_next_some() => match event { SwarmEvent::ConnectionEstablished { peer_id, .. } if peer_id == rendezvous_point => { log::info!( "Connected to rendezvous point, discovering nodes in '{}' namespace ...", NAMESPACE ); swarm.behaviour_mut().rendezvous.discover( Some(rendezvous::Namespace::new(NAMESPACE.to_string()).unwrap()), None, None, rendezvous_point, ); } SwarmEvent::Behaviour(MyEvent::Rendezvous(rendezvous::client::Event::Discovered { registrations, cookie: new_cookie, .. })) => { cookie.replace(new_cookie); for registration in registrations { for address in registration.record.addresses() { let peer = registration.record.peer_id(); log::info!("Discovered peer {} at {}", peer, address); let p2p_suffix = Protocol::P2p(*peer.as_ref()); let address_with_p2p = if !address.ends_with(&Multiaddr::empty().with(p2p_suffix.clone())) { address.clone().with(p2p_suffix) } else { address.clone() }; swarm.dial(address_with_p2p).unwrap() } } } SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { peer, result: Ok(PingSuccess::Ping { rtt }), })) if peer != rendezvous_point => { log::info!("Ping to {} is {}ms", peer, rtt.as_millis()) } other => { log::debug!("Unhandled {:?}", other); } }, _ = discover_tick.tick(), if cookie.is_some() => swarm.behaviour_mut().rendezvous.discover( Some(rendezvous::Namespace::new(NAMESPACE.to_string()).unwrap()), cookie.clone(), None, rendezvous_point ) } } } #[derive(Debug)] enum MyEvent { Rendezvous(rendezvous::client::Event), Ping(PingEvent), } impl From for MyEvent { fn from(event: rendezvous::client::Event) -> Self { MyEvent::Rendezvous(event) } } impl From for MyEvent { fn from(event: PingEvent) -> Self { MyEvent::Ping(event) } } #[derive(libp2p::NetworkBehaviour)] #[behaviour(event_process = false)] #[behaviour(out_event = "MyEvent")] struct MyBehaviour { rendezvous: rendezvous::client::Behaviour, ping: Ping, }