p2p_chat/network/layer/
builder.rs1use std::str::FromStr;
3use std::sync::Arc;
4use std::time::Duration;
5
6use anyhow::Result;
7use libp2p::{ping, swarm::Swarm, Multiaddr};
8use tokio::sync::mpsc;
9use tracing::{info, warn};
10
11use crate::crypto::Identity;
12use crate::net::{build_transport, DiscoveryBehaviour};
13use crate::storage::SledMailboxStore;
14
15use super::super::behaviour::P2PBehaviour;
16use super::super::handle::NetworkHandle;
17use super::super::message::NetworkCommand;
18use super::NetworkLayer;
19
20impl NetworkLayer {
21 pub fn new(
34 identity: Arc<Identity>,
35 listen_addr: Multiaddr,
36 is_mailbox: bool,
37 bootstrap_nodes: Vec<&str>,
38 ) -> Result<(Self, NetworkHandle)> {
39 Self::new_with_mailbox_storage(identity, listen_addr, is_mailbox, None, bootstrap_nodes)
40 }
41
42 pub fn new_with_mailbox_storage(
56 identity: Arc<Identity>,
57 listen_addr: Multiaddr,
58 is_mailbox: bool,
59 mailbox_storage: Option<Arc<SledMailboxStore>>,
60 bootstrap_nodes: Vec<&str>,
61 ) -> Result<(Self, NetworkHandle)> {
62 let keypair = identity.libp2p_keypair.clone();
63 let peer_id = identity.peer_id;
64
65 let transport = build_transport(&keypair)?;
66
67 let ping_config = ping::Config::new()
68 .with_interval(Duration::from_secs(30))
69 .with_timeout(Duration::from_secs(10));
70
71 let mut behaviour = P2PBehaviour {
72 chat: crate::net::chat::create_chat_behaviour(),
73 mailbox: crate::net::mailbox::create_mailbox_behaviour(),
74 discovery: DiscoveryBehaviour::new(peer_id)?,
75 ping: ping::Behaviour::new(ping_config),
76 };
77
78 for node in bootstrap_nodes {
79 match Multiaddr::from_str(node) {
80 Ok(addr) => {
81 if let Some(peer_id) = addr.iter().find_map(|p| {
82 if let libp2p::multiaddr::Protocol::P2p(peer_id) = p {
83 Some(peer_id)
84 } else {
85 None
86 }
87 }) {
88 info!("Adding bootstrap node: {} -> {}", peer_id, addr);
89 behaviour.discovery.kademlia.add_address(&peer_id, addr);
90 } else {
91 warn!("Bootstrap address did not contain a PeerId: {}", node);
92 }
93 }
94 Err(e) => {
95 warn!("Failed to parse bootstrap address '{}': {}", node, e);
96 }
97 }
98 }
99
100 let swarm_config = libp2p::swarm::Config::with_tokio_executor()
101 .with_idle_connection_timeout(Duration::from_secs(60 * 60));
102
103 let mut swarm = Swarm::new(transport, behaviour, peer_id, swarm_config);
104 swarm.listen_on(listen_addr)?;
105
106 if let Err(e) = swarm.behaviour_mut().discovery.bootstrap() {
107 warn!("Initial DHT bootstrap failed: {}", e);
108 }
109
110 let (command_sender, command_receiver) = mpsc::unbounded_channel::<NetworkCommand>();
111
112 let network_layer = NetworkLayer {
113 swarm,
114 command_receiver,
115 pending_requests: Default::default(),
116 sync_event_tx: None,
117 ui_notify_tx: None,
118 mailbox_storage,
119 blocked_peers: Default::default(),
120 };
121
122 let handle = NetworkHandle { command_sender };
123
124 info!(
125 "Network layer initialized for peer: {} (mailbox: {})",
126 peer_id, is_mailbox
127 );
128
129 Ok((network_layer, handle))
130 }
131}