libp2p/
builder.rs

1use std::marker::PhantomData;
2
3mod phase;
4mod select_muxer;
5mod select_security;
6
7#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
8pub use phase::WebsocketError;
9pub use phase::{BehaviourError, TransportError};
10
11/// Build a [`Swarm`](libp2p_swarm::Swarm) by combining an identity, a set of
12/// [`Transport`](libp2p_core::Transport)s and a
13/// [`NetworkBehaviour`](libp2p_swarm::NetworkBehaviour).
14///
15/// ```
16/// # use libp2p::{swarm::NetworkBehaviour, SwarmBuilder};
17/// # use libp2p::core::transport::dummy::DummyTransport;
18/// # use libp2p::core::muxing::StreamMuxerBox;
19/// # use libp2p::identity::PeerId;
20/// # use std::error::Error;
21/// #
22/// # #[cfg(all(
23/// #     not(target_arch = "wasm32"),
24/// #     feature = "tokio",
25/// #     feature = "tcp",
26/// #     feature = "tls",
27/// #     feature = "noise",
28/// #     feature = "quic",
29/// #     feature = "dns",
30/// #     feature = "relay",
31/// #     feature = "websocket",
32/// # ))]
33/// # async fn build_swarm() -> Result<(), Box<dyn Error>> {
34/// #     #[derive(NetworkBehaviour)]
35/// #     #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
36/// #     struct MyBehaviour {
37/// #         relay: libp2p_relay::client::Behaviour,
38/// #     }
39///
40/// let swarm = SwarmBuilder::with_new_identity()
41///     .with_tokio()
42///     .with_tcp(
43///         Default::default(),
44///         (libp2p_tls::Config::new, libp2p_noise::Config::new),
45///         libp2p_yamux::Config::default,
46///     )?
47///     .with_quic()
48///     .with_other_transport(|_key| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
49///     .with_dns()?
50///     .with_websocket(
51///         (libp2p_tls::Config::new, libp2p_noise::Config::new),
52///         libp2p_yamux::Config::default,
53///     )
54///     .await?
55///     .with_relay_client(
56///         (libp2p_tls::Config::new, libp2p_noise::Config::new),
57///         libp2p_yamux::Config::default,
58///     )?
59///     .with_behaviour(|_key, relay| MyBehaviour { relay })?
60///     .with_swarm_config(|cfg| {
61///         // Edit cfg here.
62///         cfg
63///     })
64///     .build();
65/// #
66/// #     Ok(())
67/// # }
68/// ```
69pub struct SwarmBuilder<Provider, Phase> {
70    keypair: libp2p_identity::Keypair,
71    phantom: PhantomData<Provider>,
72    phase: Phase,
73}
74
75#[cfg(test)]
76mod tests {
77    use libp2p_core::{muxing::StreamMuxerBox, transport::dummy::DummyTransport};
78    use libp2p_identity::PeerId;
79    use libp2p_swarm::NetworkBehaviour;
80
81    use crate::SwarmBuilder;
82
83    #[test]
84    #[cfg(all(
85        feature = "tokio",
86        feature = "tcp",
87        feature = "tls",
88        feature = "noise",
89        feature = "yamux",
90    ))]
91    fn tcp() {
92        let _ = SwarmBuilder::with_new_identity()
93            .with_tokio()
94            .with_tcp(
95                Default::default(),
96                libp2p_tls::Config::new,
97                libp2p_yamux::Config::default,
98            )
99            .unwrap()
100            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
101            .unwrap()
102            .build();
103    }
104
105    #[test]
106    #[cfg(all(
107        feature = "async-std",
108        feature = "tcp",
109        feature = "tls",
110        feature = "noise",
111        feature = "yamux",
112    ))]
113    fn async_std_tcp() {
114        let _ = SwarmBuilder::with_new_identity()
115            .with_async_std()
116            .with_tcp(
117                Default::default(),
118                libp2p_tls::Config::new,
119                libp2p_yamux::Config::default,
120            )
121            .unwrap()
122            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
123            .unwrap()
124            .build();
125    }
126
127    #[test]
128    #[cfg(all(feature = "tokio", feature = "quic"))]
129    fn quic() {
130        let _ = SwarmBuilder::with_new_identity()
131            .with_tokio()
132            .with_quic()
133            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
134            .unwrap()
135            .build();
136    }
137
138    #[test]
139    #[cfg(all(feature = "tokio", feature = "quic"))]
140    fn quic_config() {
141        let _ = SwarmBuilder::with_new_identity()
142            .with_tokio()
143            .with_quic_config(|config| config)
144            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
145            .unwrap()
146            .build();
147    }
148
149    #[test]
150    #[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "yamux"))]
151    fn tcp_yamux_mplex() {
152        let _ = SwarmBuilder::with_new_identity()
153            .with_tokio()
154            .with_tcp(
155                Default::default(),
156                libp2p_tls::Config::new,
157                (libp2p_yamux::Config::default, libp2p_mplex::Config::default),
158            )
159            .unwrap()
160            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
161            .unwrap()
162            .build();
163    }
164
165    #[test]
166    #[cfg(all(
167        feature = "tokio",
168        feature = "tcp",
169        feature = "tls",
170        feature = "noise",
171        feature = "yamux"
172    ))]
173    fn tcp_tls_noise() {
174        let _ = SwarmBuilder::with_new_identity()
175            .with_tokio()
176            .with_tcp(
177                Default::default(),
178                (libp2p_tls::Config::new, libp2p_noise::Config::new),
179                (libp2p_yamux::Config::default, libp2p_mplex::Config::default),
180            )
181            .unwrap()
182            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
183            .unwrap()
184            .build();
185    }
186
187    #[test]
188    #[cfg(all(
189        feature = "tokio",
190        feature = "tcp",
191        feature = "tls",
192        feature = "noise",
193        feature = "yamux",
194        feature = "quic"
195    ))]
196    fn tcp_quic() {
197        let _ = SwarmBuilder::with_new_identity()
198            .with_tokio()
199            .with_tcp(
200                Default::default(),
201                (libp2p_tls::Config::new, libp2p_noise::Config::new),
202                libp2p_yamux::Config::default,
203            )
204            .unwrap()
205            .with_quic()
206            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
207            .unwrap()
208            .build();
209    }
210
211    #[test]
212    #[cfg(all(
213        feature = "tokio",
214        feature = "tcp",
215        feature = "tls",
216        feature = "noise",
217        feature = "yamux",
218        feature = "quic"
219    ))]
220    fn tcp_quic_config() {
221        let _ = SwarmBuilder::with_new_identity()
222            .with_tokio()
223            .with_tcp(
224                Default::default(),
225                (libp2p_tls::Config::new, libp2p_noise::Config::new),
226                libp2p_yamux::Config::default,
227            )
228            .unwrap()
229            .with_quic_config(|config| config)
230            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
231            .unwrap()
232            .build();
233    }
234
235    #[test]
236    #[cfg(all(
237        feature = "tokio",
238        feature = "tcp",
239        feature = "tls",
240        feature = "noise",
241        feature = "yamux",
242        feature = "relay"
243    ))]
244    fn tcp_relay() {
245        #[derive(libp2p_swarm::NetworkBehaviour)]
246        #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
247        struct Behaviour {
248            dummy: libp2p_swarm::dummy::Behaviour,
249            relay: libp2p_relay::client::Behaviour,
250        }
251
252        let _ = SwarmBuilder::with_new_identity()
253            .with_tokio()
254            .with_tcp(
255                Default::default(),
256                libp2p_tls::Config::new,
257                libp2p_yamux::Config::default,
258            )
259            .unwrap()
260            .with_relay_client(libp2p_tls::Config::new, libp2p_yamux::Config::default)
261            .unwrap()
262            .with_behaviour(|_, relay| Behaviour {
263                dummy: libp2p_swarm::dummy::Behaviour,
264                relay,
265            })
266            .unwrap()
267            .build();
268    }
269
270    #[tokio::test]
271    #[cfg(all(
272        feature = "tokio",
273        feature = "tcp",
274        feature = "tls",
275        feature = "noise",
276        feature = "yamux",
277        feature = "dns"
278    ))]
279    async fn tcp_dns() {
280        SwarmBuilder::with_new_identity()
281            .with_tokio()
282            .with_tcp(
283                Default::default(),
284                (libp2p_tls::Config::new, libp2p_noise::Config::new),
285                libp2p_yamux::Config::default,
286            )
287            .unwrap()
288            .with_dns()
289            .unwrap()
290            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
291            .unwrap()
292            .build();
293    }
294
295    #[tokio::test]
296    #[cfg(all(
297        feature = "tokio",
298        feature = "tcp",
299        feature = "noise",
300        feature = "yamux",
301        feature = "dns"
302    ))]
303    async fn tcp_dns_config() {
304        SwarmBuilder::with_new_identity()
305            .with_tokio()
306            .with_tcp(
307                Default::default(),
308                (libp2p_tls::Config::new, libp2p_noise::Config::new),
309                libp2p_yamux::Config::default,
310            )
311            .unwrap()
312            .with_dns_config(
313                libp2p_dns::ResolverConfig::default(),
314                libp2p_dns::ResolverOpts::default(),
315            )
316            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
317            .unwrap()
318            .build();
319    }
320
321    #[tokio::test]
322    #[cfg(all(feature = "tokio", feature = "quic", feature = "dns"))]
323    async fn quic_dns_config() {
324        SwarmBuilder::with_new_identity()
325            .with_tokio()
326            .with_quic()
327            .with_dns_config(
328                libp2p_dns::ResolverConfig::default(),
329                libp2p_dns::ResolverOpts::default(),
330            )
331            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
332            .unwrap()
333            .build();
334    }
335
336    #[tokio::test]
337    #[cfg(all(
338        feature = "tokio",
339        feature = "tcp",
340        feature = "noise",
341        feature = "yamux",
342        feature = "quic",
343        feature = "dns"
344    ))]
345    async fn tcp_quic_dns_config() {
346        SwarmBuilder::with_new_identity()
347            .with_tokio()
348            .with_tcp(
349                Default::default(),
350                (libp2p_tls::Config::new, libp2p_noise::Config::new),
351                libp2p_yamux::Config::default,
352            )
353            .unwrap()
354            .with_quic()
355            .with_dns_config(
356                libp2p_dns::ResolverConfig::default(),
357                libp2p_dns::ResolverOpts::default(),
358            )
359            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
360            .unwrap()
361            .build();
362    }
363
364    /// Showcases how to provide custom transports unknown to the libp2p crate, e.g. WebRTC.
365    #[test]
366    #[cfg(feature = "tokio")]
367    fn other_transport() -> Result<(), Box<dyn std::error::Error>> {
368        let _ = SwarmBuilder::with_new_identity()
369            .with_tokio()
370            // Closure can either return a Transport directly.
371            .with_other_transport(|_| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
372            // Or a Result containing a Transport.
373            .with_other_transport(|_| {
374                if true {
375                    Ok(DummyTransport::<(PeerId, StreamMuxerBox)>::new())
376                } else {
377                    Err(Box::from("test"))
378                }
379            })?
380            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
381            .unwrap()
382            .build();
383
384        Ok(())
385    }
386
387    #[tokio::test]
388    #[cfg(all(
389        feature = "tokio",
390        feature = "tcp",
391        feature = "tls",
392        feature = "noise",
393        feature = "yamux",
394        feature = "dns",
395        feature = "websocket",
396    ))]
397    async fn tcp_websocket() {
398        let _ = SwarmBuilder::with_new_identity()
399            .with_tokio()
400            .with_tcp(
401                Default::default(),
402                (libp2p_tls::Config::new, libp2p_noise::Config::new),
403                libp2p_yamux::Config::default,
404            )
405            .unwrap()
406            .with_websocket(
407                (libp2p_tls::Config::new, libp2p_noise::Config::new),
408                libp2p_yamux::Config::default,
409            )
410            .await
411            .unwrap()
412            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
413            .unwrap()
414            .build();
415    }
416
417    #[tokio::test]
418    #[cfg(all(
419        feature = "tokio",
420        feature = "tcp",
421        feature = "tls",
422        feature = "noise",
423        feature = "yamux",
424        feature = "quic",
425        feature = "dns",
426        feature = "relay",
427        feature = "websocket",
428        feature = "metrics",
429    ))]
430    async fn all() {
431        #[derive(NetworkBehaviour)]
432        #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
433        struct MyBehaviour {
434            relay: libp2p_relay::client::Behaviour,
435        }
436
437        let _ = SwarmBuilder::with_new_identity()
438            .with_tokio()
439            .with_tcp(
440                Default::default(),
441                libp2p_tls::Config::new,
442                libp2p_yamux::Config::default,
443            )
444            .unwrap()
445            .with_quic()
446            .with_dns()
447            .unwrap()
448            .with_websocket(libp2p_tls::Config::new, libp2p_yamux::Config::default)
449            .await
450            .unwrap()
451            .with_relay_client(libp2p_tls::Config::new, libp2p_yamux::Config::default)
452            .unwrap()
453            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
454            .with_behaviour(|_key, relay| MyBehaviour { relay })
455            .unwrap()
456            .build();
457    }
458
459    #[test]
460    #[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "yamux"))]
461    fn tcp_bandwidth_metrics() -> Result<(), Box<dyn std::error::Error>> {
462        let _ = SwarmBuilder::with_new_identity()
463            .with_tokio()
464            .with_tcp(
465                Default::default(),
466                libp2p_tls::Config::new,
467                libp2p_yamux::Config::default,
468            )?
469            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
470            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
471            .unwrap()
472            .build();
473
474        Ok(())
475    }
476
477    #[test]
478    #[cfg(all(feature = "tokio", feature = "quic"))]
479    fn quic_bandwidth_metrics() {
480        let _ = SwarmBuilder::with_new_identity()
481            .with_tokio()
482            .with_quic()
483            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
484            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
485            .unwrap()
486            .build();
487    }
488
489    #[test]
490    #[cfg(feature = "tokio")]
491    fn other_transport_bandwidth_metrics() -> Result<(), Box<dyn std::error::Error>> {
492        let _ = SwarmBuilder::with_new_identity()
493            .with_tokio()
494            .with_other_transport(|_| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
495            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
496            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
497            .unwrap()
498            .build();
499
500        Ok(())
501    }
502}