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 = "async-std", feature = "quic"))]
140    fn async_std_quic() {
141        let _ = SwarmBuilder::with_new_identity()
142            .with_async_std()
143            .with_quic()
144            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
145            .unwrap()
146            .build();
147    }
148
149    #[test]
150    #[cfg(all(feature = "tokio", feature = "quic"))]
151    fn quic_config() {
152        let _ = SwarmBuilder::with_new_identity()
153            .with_tokio()
154            .with_quic_config(|config| config)
155            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
156            .unwrap()
157            .build();
158    }
159
160    #[test]
161    #[cfg(all(feature = "async-std", feature = "quic"))]
162    fn async_std_quic_config() {
163        let _ = SwarmBuilder::with_new_identity()
164            .with_async_std()
165            .with_quic_config(|config| config)
166            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
167            .unwrap()
168            .build();
169    }
170
171    #[test]
172    #[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "yamux"))]
173    fn tcp_yamux_mplex() {
174        let _ = SwarmBuilder::with_new_identity()
175            .with_tokio()
176            .with_tcp(
177                Default::default(),
178                libp2p_tls::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    ))]
195    fn tcp_tls_noise() {
196        let _ = SwarmBuilder::with_new_identity()
197            .with_tokio()
198            .with_tcp(
199                Default::default(),
200                (libp2p_tls::Config::new, libp2p_noise::Config::new),
201                (libp2p_yamux::Config::default, libp2p_mplex::Config::default),
202            )
203            .unwrap()
204            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
205            .unwrap()
206            .build();
207    }
208
209    #[test]
210    #[cfg(all(
211        feature = "tokio",
212        feature = "tcp",
213        feature = "tls",
214        feature = "noise",
215        feature = "yamux",
216        feature = "quic"
217    ))]
218    fn tcp_quic() {
219        let _ = SwarmBuilder::with_new_identity()
220            .with_tokio()
221            .with_tcp(
222                Default::default(),
223                (libp2p_tls::Config::new, libp2p_noise::Config::new),
224                libp2p_yamux::Config::default,
225            )
226            .unwrap()
227            .with_quic()
228            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
229            .unwrap()
230            .build();
231    }
232
233    #[test]
234    #[cfg(all(
235        feature = "async-std",
236        feature = "tcp",
237        feature = "tls",
238        feature = "noise",
239        feature = "yamux",
240        feature = "quic"
241    ))]
242    fn async_std_tcp_quic() {
243        let _ = SwarmBuilder::with_new_identity()
244            .with_async_std()
245            .with_tcp(
246                Default::default(),
247                (libp2p_tls::Config::new, libp2p_noise::Config::new),
248                libp2p_yamux::Config::default,
249            )
250            .unwrap()
251            .with_quic()
252            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
253            .unwrap()
254            .build();
255    }
256
257    #[test]
258    #[cfg(all(
259        feature = "tokio",
260        feature = "tcp",
261        feature = "tls",
262        feature = "noise",
263        feature = "yamux",
264        feature = "quic"
265    ))]
266    fn tcp_quic_config() {
267        let _ = SwarmBuilder::with_new_identity()
268            .with_tokio()
269            .with_tcp(
270                Default::default(),
271                (libp2p_tls::Config::new, libp2p_noise::Config::new),
272                libp2p_yamux::Config::default,
273            )
274            .unwrap()
275            .with_quic_config(|config| config)
276            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
277            .unwrap()
278            .build();
279    }
280
281    #[test]
282    #[cfg(all(
283        feature = "async-std",
284        feature = "tcp",
285        feature = "tls",
286        feature = "noise",
287        feature = "yamux",
288        feature = "quic"
289    ))]
290    fn async_std_tcp_quic_config() {
291        let _ = SwarmBuilder::with_new_identity()
292            .with_async_std()
293            .with_tcp(
294                Default::default(),
295                (libp2p_tls::Config::new, libp2p_noise::Config::new),
296                libp2p_yamux::Config::default,
297            )
298            .unwrap()
299            .with_quic_config(|config| config)
300            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
301            .unwrap()
302            .build();
303    }
304
305    #[test]
306    #[cfg(all(
307        feature = "tokio",
308        feature = "tcp",
309        feature = "tls",
310        feature = "noise",
311        feature = "yamux",
312        feature = "relay"
313    ))]
314    fn tcp_relay() {
315        #[derive(libp2p_swarm::NetworkBehaviour)]
316        #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
317        struct Behaviour {
318            dummy: libp2p_swarm::dummy::Behaviour,
319            relay: libp2p_relay::client::Behaviour,
320        }
321
322        let _ = SwarmBuilder::with_new_identity()
323            .with_tokio()
324            .with_tcp(
325                Default::default(),
326                libp2p_tls::Config::new,
327                libp2p_yamux::Config::default,
328            )
329            .unwrap()
330            .with_relay_client(libp2p_tls::Config::new, libp2p_yamux::Config::default)
331            .unwrap()
332            .with_behaviour(|_, relay| Behaviour {
333                dummy: libp2p_swarm::dummy::Behaviour,
334                relay,
335            })
336            .unwrap()
337            .build();
338    }
339
340    #[tokio::test]
341    #[cfg(all(
342        feature = "tokio",
343        feature = "tcp",
344        feature = "tls",
345        feature = "noise",
346        feature = "yamux",
347        feature = "dns"
348    ))]
349    async fn tcp_dns() {
350        SwarmBuilder::with_new_identity()
351            .with_tokio()
352            .with_tcp(
353                Default::default(),
354                (libp2p_tls::Config::new, libp2p_noise::Config::new),
355                libp2p_yamux::Config::default,
356            )
357            .unwrap()
358            .with_dns()
359            .unwrap()
360            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
361            .unwrap()
362            .build();
363    }
364
365    #[tokio::test]
366    #[cfg(all(
367        feature = "tokio",
368        feature = "tcp",
369        feature = "noise",
370        feature = "yamux",
371        feature = "dns"
372    ))]
373    async fn tcp_dns_config() {
374        SwarmBuilder::with_new_identity()
375            .with_tokio()
376            .with_tcp(
377                Default::default(),
378                (libp2p_tls::Config::new, libp2p_noise::Config::new),
379                libp2p_yamux::Config::default,
380            )
381            .unwrap()
382            .with_dns_config(
383                libp2p_dns::ResolverConfig::default(),
384                libp2p_dns::ResolverOpts::default(),
385            )
386            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
387            .unwrap()
388            .build();
389    }
390
391    #[tokio::test]
392    #[cfg(all(feature = "tokio", feature = "quic", feature = "dns"))]
393    async fn quic_dns_config() {
394        SwarmBuilder::with_new_identity()
395            .with_tokio()
396            .with_quic()
397            .with_dns_config(
398                libp2p_dns::ResolverConfig::default(),
399                libp2p_dns::ResolverOpts::default(),
400            )
401            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
402            .unwrap()
403            .build();
404    }
405
406    #[tokio::test]
407    #[cfg(all(
408        feature = "tokio",
409        feature = "tcp",
410        feature = "noise",
411        feature = "yamux",
412        feature = "quic",
413        feature = "dns"
414    ))]
415    async fn tcp_quic_dns_config() {
416        SwarmBuilder::with_new_identity()
417            .with_tokio()
418            .with_tcp(
419                Default::default(),
420                (libp2p_tls::Config::new, libp2p_noise::Config::new),
421                libp2p_yamux::Config::default,
422            )
423            .unwrap()
424            .with_quic()
425            .with_dns_config(
426                libp2p_dns::ResolverConfig::default(),
427                libp2p_dns::ResolverOpts::default(),
428            )
429            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
430            .unwrap()
431            .build();
432    }
433
434    #[tokio::test]
435    #[cfg(all(
436        feature = "async-std",
437        feature = "tcp",
438        feature = "noise",
439        feature = "yamux",
440        feature = "quic",
441        feature = "dns"
442    ))]
443    async fn async_std_tcp_quic_dns_config() {
444        SwarmBuilder::with_new_identity()
445            .with_async_std()
446            .with_tcp(
447                Default::default(),
448                (libp2p_tls::Config::new, libp2p_noise::Config::new),
449                libp2p_yamux::Config::default,
450            )
451            .unwrap()
452            .with_quic()
453            .with_dns_config(
454                libp2p_dns::ResolverConfig::default(),
455                libp2p_dns::ResolverOpts::default(),
456            )
457            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
458            .unwrap()
459            .build();
460    }
461
462    /// Showcases how to provide custom transports unknown to the libp2p crate, e.g. WebRTC.
463    #[test]
464    #[cfg(feature = "tokio")]
465    fn other_transport() -> Result<(), Box<dyn std::error::Error>> {
466        let _ = SwarmBuilder::with_new_identity()
467            .with_tokio()
468            // Closure can either return a Transport directly.
469            .with_other_transport(|_| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
470            // Or a Result containing a Transport.
471            .with_other_transport(|_| {
472                if true {
473                    Ok(DummyTransport::<(PeerId, StreamMuxerBox)>::new())
474                } else {
475                    Err(Box::from("test"))
476                }
477            })?
478            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
479            .unwrap()
480            .build();
481
482        Ok(())
483    }
484
485    #[tokio::test]
486    #[cfg(all(
487        feature = "tokio",
488        feature = "tcp",
489        feature = "tls",
490        feature = "noise",
491        feature = "yamux",
492        feature = "dns",
493        feature = "websocket",
494    ))]
495    async fn tcp_websocket() {
496        let _ = SwarmBuilder::with_new_identity()
497            .with_tokio()
498            .with_tcp(
499                Default::default(),
500                (libp2p_tls::Config::new, libp2p_noise::Config::new),
501                libp2p_yamux::Config::default,
502            )
503            .unwrap()
504            .with_websocket(
505                (libp2p_tls::Config::new, libp2p_noise::Config::new),
506                libp2p_yamux::Config::default,
507            )
508            .await
509            .unwrap()
510            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
511            .unwrap()
512            .build();
513    }
514
515    #[tokio::test]
516    #[cfg(all(
517        feature = "tokio",
518        feature = "tcp",
519        feature = "tls",
520        feature = "noise",
521        feature = "yamux",
522        feature = "quic",
523        feature = "dns",
524        feature = "relay",
525        feature = "websocket",
526        feature = "metrics",
527    ))]
528    async fn all() {
529        #[derive(NetworkBehaviour)]
530        #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
531        struct MyBehaviour {
532            relay: libp2p_relay::client::Behaviour,
533        }
534
535        let _ = SwarmBuilder::with_new_identity()
536            .with_tokio()
537            .with_tcp(
538                Default::default(),
539                libp2p_tls::Config::new,
540                libp2p_yamux::Config::default,
541            )
542            .unwrap()
543            .with_quic()
544            .with_dns()
545            .unwrap()
546            .with_websocket(libp2p_tls::Config::new, libp2p_yamux::Config::default)
547            .await
548            .unwrap()
549            .with_relay_client(libp2p_tls::Config::new, libp2p_yamux::Config::default)
550            .unwrap()
551            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
552            .with_behaviour(|_key, relay| MyBehaviour { relay })
553            .unwrap()
554            .build();
555    }
556
557    #[test]
558    #[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "yamux"))]
559    fn tcp_bandwidth_metrics() -> Result<(), Box<dyn std::error::Error>> {
560        let _ = SwarmBuilder::with_new_identity()
561            .with_tokio()
562            .with_tcp(
563                Default::default(),
564                libp2p_tls::Config::new,
565                libp2p_yamux::Config::default,
566            )?
567            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
568            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
569            .unwrap()
570            .build();
571
572        Ok(())
573    }
574
575    #[test]
576    #[cfg(all(feature = "tokio", feature = "quic"))]
577    fn quic_bandwidth_metrics() {
578        let _ = SwarmBuilder::with_new_identity()
579            .with_tokio()
580            .with_quic()
581            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
582            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
583            .unwrap()
584            .build();
585    }
586
587    #[test]
588    #[cfg(feature = "tokio")]
589    fn other_transport_bandwidth_metrics() -> Result<(), Box<dyn std::error::Error>> {
590        let _ = SwarmBuilder::with_new_identity()
591            .with_tokio()
592            .with_other_transport(|_| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
593            .with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
594            .with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
595            .unwrap()
596            .build();
597
598        Ok(())
599    }
600}