rzv_identify/
rzv-identify.rs

1// Copyright 2021 COMIT Network.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use std::time::Duration;
22
23use futures::StreamExt;
24use libp2p::{
25    identify, noise, ping, rendezvous,
26    swarm::{NetworkBehaviour, SwarmEvent},
27    tcp, yamux, Multiaddr,
28};
29use tracing_subscriber::EnvFilter;
30
31#[tokio::main]
32async fn main() {
33    let _ = tracing_subscriber::fmt()
34        .with_env_filter(EnvFilter::from_default_env())
35        .try_init();
36
37    let rendezvous_point_address = "/ip4/127.0.0.1/tcp/62649".parse::<Multiaddr>().unwrap();
38    let rendezvous_point = "12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN"
39        .parse()
40        .unwrap();
41
42    let mut swarm = libp2p::SwarmBuilder::with_new_identity()
43        .with_tokio()
44        .with_tcp(
45            tcp::Config::default(),
46            noise::Config::new,
47            yamux::Config::default,
48        )
49        .unwrap()
50        .with_behaviour(|key| MyBehaviour {
51            identify: identify::Behaviour::new(identify::Config::new(
52                "rendezvous-example/1.0.0".to_string(),
53                key.public(),
54            )),
55            rendezvous: rendezvous::client::Behaviour::new(key.clone()),
56            ping: ping::Behaviour::new(ping::Config::new().with_interval(Duration::from_secs(1))),
57        })
58        .unwrap()
59        .build();
60
61    let _ = swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap());
62
63    swarm.dial(rendezvous_point_address.clone()).unwrap();
64
65    while let Some(event) = swarm.next().await {
66        match event {
67            SwarmEvent::NewListenAddr { address, .. } => {
68                tracing::info!("Listening on {}", address);
69            }
70            SwarmEvent::ConnectionClosed {
71                peer_id,
72                cause: Some(error),
73                ..
74            } if peer_id == rendezvous_point => {
75                tracing::error!("Lost connection to rendezvous point {}", error);
76            }
77            // once `/identify` did its job, we know our external address and can register
78            SwarmEvent::Behaviour(MyBehaviourEvent::Identify(identify::Event::Received {
79                info,
80                ..
81            })) => {
82                // Register our external address. Needs to be done explicitly
83                // for this case, as it's a local address.
84                swarm.add_external_address(info.observed_addr);
85                if let Err(error) = swarm.behaviour_mut().rendezvous.register(
86                    rendezvous::Namespace::from_static("rendezvous"),
87                    rendezvous_point,
88                    None,
89                ) {
90                    tracing::error!("Failed to register: {error}");
91                    return;
92                }
93            }
94            SwarmEvent::Behaviour(MyBehaviourEvent::Rendezvous(
95                rendezvous::client::Event::Registered {
96                    namespace,
97                    ttl,
98                    rendezvous_node,
99                },
100            )) => {
101                tracing::info!(
102                    "Registered for namespace '{}' at rendezvous point {} for the next {} seconds",
103                    namespace,
104                    rendezvous_node,
105                    ttl
106                );
107            }
108            SwarmEvent::Behaviour(MyBehaviourEvent::Rendezvous(
109                rendezvous::client::Event::RegisterFailed {
110                    rendezvous_node,
111                    namespace,
112                    error,
113                },
114            )) => {
115                tracing::error!(
116                    "Failed to register: rendezvous_node={}, namespace={}, error_code={:?}",
117                    rendezvous_node,
118                    namespace,
119                    error
120                );
121                return;
122            }
123            SwarmEvent::Behaviour(MyBehaviourEvent::Ping(ping::Event {
124                peer,
125                result: Ok(rtt),
126                ..
127            })) if peer != rendezvous_point => {
128                tracing::info!("Ping to {} is {}ms", peer, rtt.as_millis())
129            }
130            other => {
131                tracing::debug!("Unhandled {:?}", other);
132            }
133        }
134    }
135}
136
137#[derive(NetworkBehaviour)]
138struct MyBehaviour {
139    identify: identify::Behaviour,
140    rendezvous: rendezvous::client::Behaviour,
141    ping: ping::Behaviour,
142}