network_libp2p/native/
mod.rs1use chat_core::error::ChatResult;
2use chat_core::network::{Multiaddr, NetworkEvent};
3use futures::StreamExt;
4use libp2p::{identity, noise, PeerId};
5
6use crate::behaviour::build_chat_behaviour;
7use crate::bootstrap::bootstrap_swarm;
8use crate::common::{init_libp2p_network, Libp2pNetwork};
9use crate::NodeOptions;
10
11pub async fn build_node(options: NodeOptions) -> ChatResult<Libp2pNetwork> {
13 let keypair = identity::Keypair::generate_ed25519();
14 build_node_with_keypair(options, keypair).await
15}
16
17pub async fn build_node_with_keypair(
19 options: NodeOptions,
20 keypair: identity::Keypair,
21) -> ChatResult<Libp2pNetwork> {
22 let local_peer_id = PeerId::from(keypair.public());
23
24 let webrtc_cert = libp2p_webrtc::tokio::Certificate::generate(&mut rand::thread_rng())
26 .map_err(|e| e.to_string())?;
27
28 let builder = libp2p::SwarmBuilder::with_existing_identity(keypair.clone())
31 .with_tokio()
32 .with_tcp(
33 libp2p::tcp::Config::default(),
34 noise::Config::new,
35 libp2p::yamux::Config::default,
36 )
37 .map_err(|e| e.to_string())?
38 .with_quic();
39
40 let builder = builder
41 .with_other_transport(|keypair| {
42 let webrtc = libp2p_webrtc::tokio::Transport::new(
43 keypair.clone(),
44 webrtc_cert,
45 );
46 Ok(webrtc)
47 })
48 .map_err(|e| e.to_string())?;
49
50 let builder = builder
51 .with_dns()
52 .map_err(|e| e.to_string())?
53 .with_websocket(noise::Config::new, libp2p::yamux::Config::default)
54 .await
55 .map_err(|e| e.to_string())?;
56
57 let builder = builder
58 .with_relay_client(noise::Config::new, libp2p::yamux::Config::default)
59 .map_err(|e| e.to_string())?;
60
61 let mut swarm = builder
62 .with_behaviour(|keypair, relay_client| {
63 build_chat_behaviour(keypair, local_peer_id, relay_client, &options)
64 })
65 .map_err(|e| e.to_string())?
66 .with_swarm_config(|cfg| {
67 cfg.with_idle_connection_timeout(std::time::Duration::from_secs(60))
68 })
69 .build();
70
71 swarm
73 .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap())
74 .map_err(|e| e.to_string())?;
75 swarm
76 .listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse().unwrap())
77 .map_err(|e| e.to_string())?;
78 swarm
79 .listen_on("/ip4/0.0.0.0/udp/0/webrtc-direct".parse().unwrap())
80 .map_err(|e| e.to_string())?;
81
82 for addr in &options.listen_addresses {
84 let multiaddr = addr.parse().map_err(|e: libp2p::multiaddr::Error| e.to_string())?;
85 swarm.listen_on(multiaddr).map_err(|e| e.to_string())?;
86 }
87
88 let bootstrap_peer_ids = bootstrap_swarm(&mut swarm, &options);
89
90 Ok(init_libp2p_network(swarm, local_peer_id, &options, bootstrap_peer_ids))
91}
92
93impl Libp2pNetwork {
96 pub(crate) fn platform_dial_addrs(&self) -> Vec<Multiaddr> {
97 let mut addrs: Vec<Multiaddr> = self.swarm.listeners().map(|a| Multiaddr::from(a.to_string())).collect();
98 addrs.extend(
99 self.swarm
100 .external_addresses()
101 .filter(|a| {
102 let s = a.to_string();
103 s.contains("p2p-circuit") || s.contains("webrtc")
104 })
105 .map(|a| Multiaddr::from(a.to_string())),
106 );
107 addrs
108 }
109
110 pub(crate) async fn platform_next_event(&mut self) -> Option<NetworkEvent> {
111 use libp2p::swarm::SwarmEvent;
112 loop {
113 let event = self.swarm.select_next_some().await;
114 if let Some(ev) = match event {
115 SwarmEvent::Behaviour(crate::behaviour::ChatBehaviourEvent::Dcutr(ev)) => {
116 match ev.result {
117 Ok(_) => {
118 tracing::info!("DCUtR succeeded with {}", ev.remote_peer_id);
119 }
120 Err(ref e) => {
121 tracing::warn!(
122 "DCUtR failed with {}: {}",
123 ev.remote_peer_id,
124 e
125 );
126 }
127 }
128 None
129 }
130 SwarmEvent::Behaviour(crate::behaviour::ChatBehaviourEvent::Autonat(ev)) => {
131 match ev {
132 libp2p::autonat::Event::StatusChanged { old, new } => {
133 tracing::info!("AutoNAT status changed: {:?} -> {:?}", old, new);
134 }
135 other => {
136 tracing::debug!("AutoNAT event: {:?}", other);
137 }
138 }
139 None
140 }
141 other => self.handle_swarm_event(other),
142 } {
143 return Some(ev);
144 }
145 }
146 }
147}