Skip to main content

rust_ipfs/p2p/
behaviour.rs

1use super::{addressbook, protocol};
2
3use super::peerbook::{self};
4use serde::{Deserialize, Serialize};
5
6use crate::repo::DefaultStorage;
7use crate::{IntoAddPeerOpt, IpfsOptions};
8
9use crate::repo::Repo;
10
11use ipld_core::cid::Cid;
12
13use connexa::prelude::dht::Record;
14use connexa::prelude::identity::{Keypair, PublicKey};
15use connexa::prelude::swarm::behaviour::toggle::Toggle;
16use connexa::prelude::swarm::NetworkBehaviour;
17use connexa::prelude::{identify, relay, Multiaddr, PeerId};
18use std::fmt::Debug;
19use std::num::NonZeroU32;
20use std::time::Duration;
21
22/// Behaviour type.
23#[derive(NetworkBehaviour)]
24#[behaviour(prelude = "connexa::prelude::swarm::derive_prelude")]
25pub struct Behaviour<C>
26where
27    C: NetworkBehaviour,
28    <C as NetworkBehaviour>::ToSwarm: Debug + Send,
29{
30    pub addressbook: addressbook::Behaviour,
31
32    pub bitswap: Toggle<super::bitswap::Behaviour>,
33
34    // custom behaviours
35    pub custom: Toggle<C>,
36
37    // misc
38    pub peerbook: peerbook::Behaviour,
39    pub protocol: protocol::Behaviour,
40}
41
42/// Represents the result of a Kademlia query.
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum KadResult {
45    /// The query has been exhausted.
46    Complete,
47    /// The query successfully returns `GetClosestPeers` or `GetProviders` results.
48    Peers(Vec<PeerId>),
49    /// The query successfully returns a `GetRecord` result.
50    Records(Vec<Record>),
51    Record(Record),
52}
53
54#[derive(Serialize, Deserialize, Clone, Debug)]
55pub struct RelayConfig {
56    pub max_reservations: usize,
57    pub max_reservations_per_peer: usize,
58    pub reservation_duration: Duration,
59    pub reservation_rate_limiters: Vec<RateLimit>,
60
61    pub max_circuits: usize,
62    pub max_circuits_per_peer: usize,
63    pub max_circuit_duration: Duration,
64    pub max_circuit_bytes: u64,
65    pub circuit_src_rate_limiters: Vec<RateLimit>,
66}
67
68impl Default for RelayConfig {
69    fn default() -> Self {
70        let limiters = vec![
71            RateLimit::PerPeer {
72                limit: NonZeroU32::new(30).expect("30 > 0"),
73                interval: Duration::from_secs(60 * 2),
74            },
75            RateLimit::PerIp {
76                limit: NonZeroU32::new(60).expect("60 > 0"),
77                interval: Duration::from_secs(60),
78            },
79        ];
80        Self {
81            max_reservations: 128,
82            max_reservations_per_peer: 4,
83            reservation_duration: Duration::from_secs(60 * 60),
84            reservation_rate_limiters: limiters.clone(),
85            max_circuits: 16,
86            max_circuits_per_peer: 4,
87            max_circuit_duration: Duration::from_secs(2 * 60),
88            max_circuit_bytes: 1 << 17,
89            circuit_src_rate_limiters: limiters,
90        }
91    }
92}
93
94impl RelayConfig {
95    /// Configuration to allow a connection to the relay without limits
96    pub fn unbounded() -> Self {
97        Self {
98            max_circuits: usize::MAX,
99            max_circuit_bytes: u64::MAX,
100            max_circuit_duration: Duration::MAX,
101            max_circuits_per_peer: usize::MAX,
102            max_reservations: usize::MAX,
103            reservation_duration: Duration::MAX,
104            max_reservations_per_peer: usize::MAX,
105            reservation_rate_limiters: vec![],
106            circuit_src_rate_limiters: vec![],
107        }
108    }
109}
110
111#[derive(Serialize, Deserialize, Clone, Debug)]
112pub struct IdentifyConfiguration {
113    pub protocol_version: String,
114    pub agent_version: String,
115    pub interval: Duration,
116    pub push_update: bool,
117    pub cache: usize,
118}
119
120impl Default for IdentifyConfiguration {
121    fn default() -> Self {
122        Self {
123            protocol_version: "/ipfs/0.1.0".into(),
124            agent_version: "rust-ipfs".into(),
125            interval: Duration::from_secs(5 * 60),
126            push_update: true,
127            cache: 100,
128        }
129    }
130}
131
132impl IdentifyConfiguration {
133    pub fn into(self, publuc_key: PublicKey) -> identify::Config {
134        identify::Config::new(self.protocol_version, publuc_key)
135            .with_agent_version(self.agent_version)
136            .with_interval(self.interval)
137            .with_push_listen_addr_updates(self.push_update)
138            .with_cache_size(self.cache)
139    }
140}
141
142impl From<RelayConfig> for relay::server::Config {
143    fn from(
144        RelayConfig {
145            max_reservations,
146            max_reservations_per_peer,
147            reservation_duration,
148            max_circuits,
149            max_circuits_per_peer,
150            max_circuit_duration,
151            max_circuit_bytes,
152            reservation_rate_limiters,
153            circuit_src_rate_limiters,
154        }: RelayConfig,
155    ) -> Self {
156        let reservation_duration = max_duration(reservation_duration);
157        let max_circuit_duration = max_duration(max_circuit_duration);
158
159        let mut config = relay::server::Config {
160            max_reservations,
161            max_reservations_per_peer,
162            reservation_duration,
163            max_circuits,
164            max_circuits_per_peer,
165            max_circuit_duration,
166            max_circuit_bytes,
167            ..Default::default()
168        };
169
170        for rate in circuit_src_rate_limiters {
171            match rate {
172                RateLimit::PerPeer { limit, interval } => {
173                    config = config.circuit_src_per_peer(limit, interval);
174                }
175                RateLimit::PerIp { limit, interval } => {
176                    config = config.circuit_src_per_ip(limit, interval);
177                }
178            }
179        }
180
181        for rate in reservation_rate_limiters {
182            match rate {
183                RateLimit::PerPeer { limit, interval } => {
184                    config = config.reservation_rate_per_peer(limit, interval);
185                }
186                RateLimit::PerIp { limit, interval } => {
187                    config = config.reservation_rate_per_ip(limit, interval);
188                }
189            }
190        }
191
192        config
193    }
194}
195
196fn max_duration(duration: Duration) -> Duration {
197    let start = web_time::Instant::now();
198    if start.checked_add(duration).is_none() {
199        return Duration::from_secs(u32::MAX as _);
200    }
201    duration
202}
203
204#[derive(Serialize, Deserialize, Clone, Debug)]
205pub enum RateLimit {
206    PerPeer {
207        limit: NonZeroU32,
208        interval: Duration,
209    },
210    PerIp {
211        limit: NonZeroU32,
212        interval: Duration,
213    },
214}
215impl<C> Behaviour<C>
216where
217    C: NetworkBehaviour,
218    <C as NetworkBehaviour>::ToSwarm: Debug + Send,
219{
220    pub(crate) fn new(
221        keypair: &Keypair,
222        options: &IpfsOptions,
223        repo: &Repo<DefaultStorage>,
224        custom: Option<C>,
225    ) -> Self {
226        let bootstrap = options.bootstrap.clone();
227
228        let protocols = options.protocols;
229
230        let peer_id = keypair.public().to_peer_id();
231
232        info!("net: starting with peer id {}", peer_id);
233
234        let bitswap = protocols
235            .bitswap
236            .then(|| {
237                let config = (options.bitswap_config)(super::bitswap::Config::default());
238                super::bitswap::Behaviour::new(repo, config)
239            })
240            .into();
241
242        let peerbook = peerbook::Behaviour::default();
243
244        let addressbook = addressbook::Behaviour::with_config(options.addr_config);
245
246        let protocol = protocol::Behaviour::default();
247        let custom = Toggle::from(custom);
248
249        let mut behaviour = Behaviour {
250            bitswap,
251            peerbook,
252            addressbook,
253            protocol,
254            custom,
255        };
256
257        for addr in bootstrap {
258            let Ok(mut opt) = IntoAddPeerOpt::into_opt(addr) else {
259                continue;
260            };
261
262            // explicitly dial the bootstrap peer. If the peer will be bootstrapped via kad, the additional dial will be cancelled
263            opt = opt.set_dial(true);
264
265            _ = behaviour.add_peer(opt);
266        }
267
268        behaviour
269    }
270
271    pub fn add_peer<I: IntoAddPeerOpt>(&mut self, opt: I) -> bool {
272        let opt = opt.into_opt().expect("valid entries");
273
274        self.addressbook.add_address(opt);
275
276        true
277    }
278
279    pub fn remove_peer(&mut self, peer: &PeerId) {
280        self.addressbook.remove_peer(peer);
281    }
282
283    pub fn addrs(&self) -> Vec<(PeerId, Vec<Multiaddr>)> {
284        self.peerbook.connected_peers_addrs().collect()
285    }
286
287    // TODO
288    pub fn stop_providing_block(&mut self, cid: &Cid) {
289        info!("Finished providing block {}", cid.to_string());
290        let _key = cid.hash().to_bytes();
291        // if let Some(kad) = self.kademlia.as_mut() {
292        //     kad.stop_providing(&key.into());
293        // }
294    }
295
296    pub fn supported_protocols(&self) -> Vec<String> {
297        self.protocol.iter().collect::<Vec<_>>()
298    }
299}