1#![doc = include_str!("../README.md")]
22
23use std::error::Error;
24
25use futures::StreamExt;
26use libp2p::{
27 core::Multiaddr,
28 identify, identity,
29 metrics::{Metrics, Recorder},
30 noise, ping,
31 swarm::{NetworkBehaviour, SwarmEvent},
32 tcp, yamux,
33};
34use opentelemetry::{trace::TracerProvider as _, KeyValue};
35use opentelemetry_otlp::SpanExporter;
36use opentelemetry_sdk::{runtime, trace::TracerProvider};
37use prometheus_client::registry::Registry;
38use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};
39
40mod http_service;
41
42#[tokio::main]
43async fn main() -> Result<(), Box<dyn Error>> {
44 setup_tracing()?;
45
46 let mut metric_registry = Registry::default();
47
48 let mut swarm = libp2p::SwarmBuilder::with_new_identity()
49 .with_tokio()
50 .with_tcp(
51 tcp::Config::default(),
52 noise::Config::new,
53 yamux::Config::default,
54 )?
55 .with_bandwidth_metrics(&mut metric_registry)
56 .with_behaviour(|key| Behaviour::new(key.public()))?
57 .build();
58
59 swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
60
61 if let Some(addr) = std::env::args().nth(1) {
62 let remote: Multiaddr = addr.parse()?;
63 swarm.dial(remote)?;
64 tracing::info!(address=%addr, "Dialed address")
65 }
66
67 let metrics = Metrics::new(&mut metric_registry);
68 tokio::spawn(http_service::metrics_server(metric_registry));
69
70 loop {
71 match swarm.select_next_some().await {
72 SwarmEvent::NewListenAddr { address, .. } => {
73 tracing::info!(
74 "Local node is listening on\n {}/p2p/{}",
75 address,
76 swarm.local_peer_id()
77 );
78 }
79 SwarmEvent::Behaviour(BehaviourEvent::Ping(ping_event)) => {
80 tracing::info!(?ping_event);
81 metrics.record(&ping_event);
82 }
83 SwarmEvent::Behaviour(BehaviourEvent::Identify(identify_event)) => {
84 tracing::info!(?identify_event);
85 metrics.record(&identify_event);
86 }
87 swarm_event => {
88 tracing::info!(?swarm_event);
89 metrics.record(&swarm_event);
90 }
91 }
92 }
93}
94
95fn setup_tracing() -> Result<(), Box<dyn Error>> {
96 let provider = TracerProvider::builder()
97 .with_batch_exporter(
98 SpanExporter::builder().with_tonic().build()?,
99 runtime::Tokio,
100 )
101 .with_resource(opentelemetry_sdk::Resource::new(vec![KeyValue::new(
102 "service.name",
103 "libp2p",
104 )]))
105 .build();
106 tracing_subscriber::registry()
107 .with(tracing_subscriber::fmt::layer().with_filter(EnvFilter::from_default_env()))
108 .with(
109 tracing_opentelemetry::layer()
110 .with_tracer(provider.tracer("libp2p-subscriber"))
111 .with_filter(EnvFilter::from_default_env()),
112 )
113 .init();
114
115 Ok(())
116}
117
118#[derive(NetworkBehaviour)]
120struct Behaviour {
121 identify: identify::Behaviour,
122 ping: ping::Behaviour,
123}
124
125impl Behaviour {
126 fn new(local_pub_key: identity::PublicKey) -> Self {
127 Self {
128 ping: ping::Behaviour::default(),
129 identify: identify::Behaviour::new(identify::Config::new(
130 "/ipfs/0.1.0".into(),
131 local_pub_key,
132 )),
133 }
134 }
135}