libp2p_swarm/
behaviour.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21mod either;
22mod external_addresses;
23mod listen_addresses;
24pub mod toggle;
25
26pub use external_addresses::ExternalAddresses;
27pub use listen_addresses::ListenAddresses;
28
29use crate::connection::ConnectionId;
30use crate::dial_opts::DialOpts;
31use crate::listen_opts::ListenOpts;
32use crate::{
33    ConnectionDenied, ConnectionHandler, DialError, ListenError, THandler, THandlerInEvent,
34    THandlerOutEvent,
35};
36use libp2p_core::{transport::ListenerId, ConnectedPoint, Endpoint, Multiaddr};
37use libp2p_identity::PeerId;
38use std::{task::Context, task::Poll};
39
40/// A [`NetworkBehaviour`] defines the behaviour of the local node on the network.
41///
42/// In contrast to [`Transport`](libp2p_core::Transport) which defines **how** to send bytes on the
43/// network, [`NetworkBehaviour`] defines **what** bytes to send and **to whom**.
44///
45/// Each protocol (e.g. `libp2p-ping`, `libp2p-identify` or `libp2p-kad`) implements
46/// [`NetworkBehaviour`]. Multiple implementations of [`NetworkBehaviour`] can be composed into a
47/// hierarchy of [`NetworkBehaviour`]s where parent implementations delegate to child
48/// implementations. Finally the root of the [`NetworkBehaviour`] hierarchy is passed to
49/// [`Swarm`](crate::Swarm) where it can then control the behaviour of the local node on a libp2p
50/// network.
51///
52/// # Hierarchy of [`NetworkBehaviour`]
53///
54/// To compose multiple [`NetworkBehaviour`] implementations into a single [`NetworkBehaviour`]
55/// implementation, potentially building a multi-level hierarchy of [`NetworkBehaviour`]s, one can
56/// use one of the [`NetworkBehaviour`] combinators, and/or use the [`NetworkBehaviour`] derive
57/// macro.
58///
59/// ## Combinators
60///
61/// [`NetworkBehaviour`] combinators wrap one or more [`NetworkBehaviour`] implementations and
62/// implement [`NetworkBehaviour`] themselves. Example is the
63/// [`Toggle`](crate::behaviour::toggle::Toggle) [`NetworkBehaviour`].
64///
65/// ``` rust
66/// # use libp2p_swarm::dummy;
67/// # use libp2p_swarm::behaviour::toggle::Toggle;
68/// let my_behaviour = dummy::Behaviour;
69/// let my_toggled_behaviour = Toggle::from(Some(my_behaviour));
70/// ```
71///
72/// ## Custom [`NetworkBehaviour`] with the Derive Macro
73///
74/// One can derive [`NetworkBehaviour`] for a custom `struct` via the `#[derive(NetworkBehaviour)]`
75/// proc macro re-exported by the `libp2p` crate. The macro generates a delegating `trait`
76/// implementation for the custom `struct`. Each [`NetworkBehaviour`] trait method is simply
77/// delegated to each `struct` member in the order the `struct` is defined. For example for
78/// [`NetworkBehaviour::poll`] it will first poll the first `struct` member until it returns
79/// [`Poll::Pending`] before moving on to later members.
80///
81/// Events ([`NetworkBehaviour::ToSwarm`]) returned by each `struct` member are wrapped in a new
82/// `enum` event, with an `enum` variant for each `struct` member. Users can define this event
83/// `enum` themselves and provide the name to the derive macro via `#[behaviour(to_swarm =
84/// "MyCustomOutEvent")]`. If the user does not specify an `to_swarm`, the derive macro generates
85/// the event definition itself, naming it `<STRUCT_NAME>Event`.
86///
87/// The aforementioned conversion of each of the event types generated by the struct members to the
88/// custom `to_swarm` is handled by [`From`] implementations which the user needs to define in
89/// addition to the event `enum` itself.
90///
91/// ``` rust
92/// # use libp2p_identify as identify;
93/// # use libp2p_ping as ping;
94/// # use libp2p_swarm_derive::NetworkBehaviour;
95/// #[derive(NetworkBehaviour)]
96/// #[behaviour(to_swarm = "Event")]
97/// # #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
98/// struct MyBehaviour {
99///   identify: identify::Behaviour,
100///   ping: ping::Behaviour,
101/// }
102///
103/// enum Event {
104///   Identify(identify::Event),
105///   Ping(ping::Event),
106/// }
107///
108/// impl From<identify::Event> for Event {
109///   fn from(event: identify::Event) -> Self {
110///     Self::Identify(event)
111///   }
112/// }
113///
114/// impl From<ping::Event> for Event {
115///   fn from(event: ping::Event) -> Self {
116///     Self::Ping(event)
117///   }
118/// }
119/// ```
120pub trait NetworkBehaviour: 'static {
121    /// Handler for all the protocols the network behaviour supports.
122    type ConnectionHandler: ConnectionHandler;
123
124    /// Event generated by the `NetworkBehaviour` and that the swarm will report back.
125    type ToSwarm: Send + 'static;
126
127    /// Callback that is invoked for every new inbound connection.
128    ///
129    /// At this point in the connection lifecycle, only the remote's and our local address are known.
130    /// We have also already allocated a [`ConnectionId`].
131    ///
132    /// Any error returned from this function will immediately abort the dial attempt.
133    fn handle_pending_inbound_connection(
134        &mut self,
135        _connection_id: ConnectionId,
136        _local_addr: &Multiaddr,
137        _remote_addr: &Multiaddr,
138    ) -> Result<(), ConnectionDenied> {
139        Ok(())
140    }
141
142    /// Callback that is invoked for every established inbound connection.
143    ///
144    /// This is invoked once another peer has successfully dialed us.
145    ///
146    /// At this point, we have verified their [`PeerId`] and we know, which particular [`Multiaddr`] succeeded in the dial.
147    /// In order to actually use this connection, this function must return a [`ConnectionHandler`].
148    /// Returning an error will immediately close the connection.
149    fn handle_established_inbound_connection(
150        &mut self,
151        _connection_id: ConnectionId,
152        peer: PeerId,
153        local_addr: &Multiaddr,
154        remote_addr: &Multiaddr,
155    ) -> Result<THandler<Self>, ConnectionDenied>;
156
157    /// Callback that is invoked for every outbound connection attempt.
158    ///
159    /// We have access to:
160    ///
161    /// - The [`PeerId`], if known. Remember that we can dial without a [`PeerId`].
162    /// - All addresses passed to [`DialOpts`] are passed in here too.
163    /// - The effective [`Role`](Endpoint) of this peer in the dial attempt. Typically, this is set to [`Endpoint::Dialer`] except if we are attempting a hole-punch.
164    /// - The [`ConnectionId`] identifying the future connection resulting from this dial, if successful.
165    ///
166    /// Note that the addresses returned from this function are only used for dialing if [`WithPeerIdWithAddresses::extend_addresses_through_behaviour`](crate::dial_opts::WithPeerIdWithAddresses::extend_addresses_through_behaviour) is set.
167    ///
168    /// Any error returned from this function will immediately abort the dial attempt.
169    fn handle_pending_outbound_connection(
170        &mut self,
171        _connection_id: ConnectionId,
172        _maybe_peer: Option<PeerId>,
173        _addresses: &[Multiaddr],
174        _effective_role: Endpoint,
175    ) -> Result<Vec<Multiaddr>, ConnectionDenied> {
176        Ok(vec![])
177    }
178
179    /// Callback that is invoked for every established outbound connection.
180    ///
181    /// This is invoked once we have successfully dialed a peer.
182    /// At this point, we have verified their [`PeerId`] and we know, which particular [`Multiaddr`] succeeded in the dial.
183    /// In order to actually use this connection, this function must return a [`ConnectionHandler`].
184    /// Returning an error will immediately close the connection.
185    fn handle_established_outbound_connection(
186        &mut self,
187        _connection_id: ConnectionId,
188        peer: PeerId,
189        addr: &Multiaddr,
190        role_override: Endpoint,
191    ) -> Result<THandler<Self>, ConnectionDenied>;
192
193    /// Informs the behaviour about an event from the [`Swarm`](crate::Swarm).
194    fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>);
195
196    /// Informs the behaviour about an event generated by the [`ConnectionHandler`]
197    /// dedicated to the peer identified by `peer_id`. for the behaviour.
198    ///
199    /// The [`PeerId`] is guaranteed to be in a connected state. In other words,
200    /// [`FromSwarm::ConnectionEstablished`] has previously been received with this [`PeerId`].
201    fn on_connection_handler_event(
202        &mut self,
203        _peer_id: PeerId,
204        _connection_id: ConnectionId,
205        _event: THandlerOutEvent<Self>,
206    );
207
208    /// Polls for things that swarm should do.
209    ///
210    /// This API mimics the API of the `Stream` trait. The method may register the current task in
211    /// order to wake it up at a later point in time.
212    fn poll(
213        &mut self,
214        cx: &mut Context<'_>,
215        params: &mut impl PollParameters,
216    ) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>>;
217}
218
219/// Parameters passed to `poll()`, that the `NetworkBehaviour` has access to.
220pub trait PollParameters {
221    /// Iterator returned by [`supported_protocols`](PollParameters::supported_protocols).
222    type SupportedProtocolsIter: ExactSizeIterator<Item = Vec<u8>>;
223
224    /// Returns the list of protocol the behaviour supports when a remote negotiates a protocol on
225    /// an inbound substream.
226    ///
227    /// The iterator's elements are the ASCII names as reported on the wire.
228    ///
229    /// Note that the list is computed once at initialization and never refreshed.
230    #[deprecated(
231        note = "Use `libp2p_swarm::SupportedProtocols` in your `ConnectionHandler` instead."
232    )]
233    fn supported_protocols(&self) -> Self::SupportedProtocolsIter;
234}
235
236/// A command issued from a [`NetworkBehaviour`] for the [`Swarm`].
237///
238/// [`Swarm`]: super::Swarm
239#[derive(Debug)]
240pub enum ToSwarm<TOutEvent, TInEvent> {
241    /// Instructs the `Swarm` to return an event when it is being polled.
242    GenerateEvent(TOutEvent),
243
244    /// Instructs the swarm to start a dial.
245    ///
246    /// On success, [`NetworkBehaviour::on_swarm_event`] with `ConnectionEstablished` is invoked.
247    /// On failure, [`NetworkBehaviour::on_swarm_event`] with `DialFailure` is invoked.
248    ///
249    /// [`DialOpts`] provides access to the [`ConnectionId`] via [`DialOpts::connection_id`].
250    /// This [`ConnectionId`] will be used throughout the connection's lifecycle to associate events with it.
251    /// This allows a [`NetworkBehaviour`] to identify a connection that resulted out of its own dial request.
252    Dial { opts: DialOpts },
253
254    /// Instructs the [`Swarm`](crate::Swarm) to listen on the provided address.
255    ListenOn { opts: ListenOpts },
256
257    /// Instructs the [`Swarm`](crate::Swarm) to remove the listener.
258    RemoveListener { id: ListenerId },
259
260    /// Instructs the `Swarm` to send an event to the handler dedicated to a
261    /// connection with a peer.
262    ///
263    /// If the `Swarm` is connected to the peer, the message is delivered to the [`ConnectionHandler`]
264    /// instance identified by the peer ID and connection ID.
265    ///
266    /// If the specified connection no longer exists, the event is silently dropped.
267    ///
268    /// Typically the connection ID given is the same as the one passed to
269    /// [`NetworkBehaviour::on_connection_handler_event`], i.e. whenever the behaviour wishes to
270    /// respond to a request on the same connection (and possibly the same
271    /// substream, as per the implementation of [`ConnectionHandler`]).
272    ///
273    /// Note that even if the peer is currently connected, connections can get closed
274    /// at any time and thus the event may not reach a handler.
275    NotifyHandler {
276        /// The peer for whom a [`ConnectionHandler`] should be notified.
277        peer_id: PeerId,
278        /// The options w.r.t. which connection handler to notify of the event.
279        handler: NotifyHandler,
280        /// The event to send.
281        event: TInEvent,
282    },
283
284    /// Reports a new candidate for an external address to the [`Swarm`](crate::Swarm).
285    ///
286    /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::NewExternalAddrCandidate`].
287    ///
288    /// This address could come from a variety of sources:
289    /// - A protocol such as identify obtained it from a remote.
290    /// - The user provided it based on configuration.
291    /// - We made an educated guess based on one of our listen addresses.
292    /// - We established a new relay connection.
293    NewExternalAddrCandidate(Multiaddr),
294
295    /// Indicates to the [`Swarm`](crate::Swarm) that the provided address is confirmed to be externally reachable.
296    ///
297    /// This is intended to be issued in response to a [`FromSwarm::NewExternalAddrCandidate`] if we are indeed externally reachable on this address.
298    /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrConfirmed`].
299    ExternalAddrConfirmed(Multiaddr),
300
301    /// Indicates to the [`Swarm`](crate::Swarm) that we are no longer externally reachable under the provided address.
302    ///
303    /// This expires an address that was earlier confirmed via [`ToSwarm::ExternalAddrConfirmed`].
304    /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrExpired`].
305    ExternalAddrExpired(Multiaddr),
306
307    /// Instructs the `Swarm` to initiate a graceful close of one or all connections
308    /// with the given peer.
309    ///
310    /// Note: Closing a connection via
311    /// [`ToSwarm::CloseConnection`] does not inform the
312    /// corresponding [`ConnectionHandler`].
313    /// Closing a connection via a [`ConnectionHandler`] can be done
314    /// either in a collaborative manner across [`ConnectionHandler`]s
315    /// with [`ConnectionHandler::connection_keep_alive`] or directly with
316    /// [`ConnectionHandlerEvent::Close`](crate::ConnectionHandlerEvent::Close).
317    CloseConnection {
318        /// The peer to disconnect.
319        peer_id: PeerId,
320        /// Whether to close a specific or all connections to the given peer.
321        connection: CloseConnection,
322    },
323}
324
325impl<TOutEvent, TInEventOld> ToSwarm<TOutEvent, TInEventOld> {
326    /// Map the handler event.
327    pub fn map_in<TInEventNew>(
328        self,
329        f: impl FnOnce(TInEventOld) -> TInEventNew,
330    ) -> ToSwarm<TOutEvent, TInEventNew> {
331        match self {
332            ToSwarm::GenerateEvent(e) => ToSwarm::GenerateEvent(e),
333            ToSwarm::Dial { opts } => ToSwarm::Dial { opts },
334            ToSwarm::ListenOn { opts } => ToSwarm::ListenOn { opts },
335            ToSwarm::RemoveListener { id } => ToSwarm::RemoveListener { id },
336            ToSwarm::NotifyHandler {
337                peer_id,
338                handler,
339                event,
340            } => ToSwarm::NotifyHandler {
341                peer_id,
342                handler,
343                event: f(event),
344            },
345            ToSwarm::CloseConnection {
346                peer_id,
347                connection,
348            } => ToSwarm::CloseConnection {
349                peer_id,
350                connection,
351            },
352            ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr),
353            ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr),
354            ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr),
355        }
356    }
357}
358
359impl<TOutEvent, THandlerIn> ToSwarm<TOutEvent, THandlerIn> {
360    /// Map the event the swarm will return.
361    pub fn map_out<E>(self, f: impl FnOnce(TOutEvent) -> E) -> ToSwarm<E, THandlerIn> {
362        match self {
363            ToSwarm::GenerateEvent(e) => ToSwarm::GenerateEvent(f(e)),
364            ToSwarm::Dial { opts } => ToSwarm::Dial { opts },
365            ToSwarm::ListenOn { opts } => ToSwarm::ListenOn { opts },
366            ToSwarm::RemoveListener { id } => ToSwarm::RemoveListener { id },
367            ToSwarm::NotifyHandler {
368                peer_id,
369                handler,
370                event,
371            } => ToSwarm::NotifyHandler {
372                peer_id,
373                handler,
374                event,
375            },
376            ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr),
377            ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr),
378            ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr),
379            ToSwarm::CloseConnection {
380                peer_id,
381                connection,
382            } => ToSwarm::CloseConnection {
383                peer_id,
384                connection,
385            },
386        }
387    }
388}
389
390/// The options w.r.t. which connection handler to notify of an event.
391#[derive(Debug, Clone)]
392pub enum NotifyHandler {
393    /// Notify a particular connection handler.
394    One(ConnectionId),
395    /// Notify an arbitrary connection handler.
396    Any,
397}
398
399/// The options which connections to close.
400#[derive(Debug, Clone, Default)]
401pub enum CloseConnection {
402    /// Disconnect a particular connection.
403    One(ConnectionId),
404    /// Disconnect all connections.
405    #[default]
406    All,
407}
408
409/// Enumeration with the list of the possible events
410/// to pass to [`on_swarm_event`](NetworkBehaviour::on_swarm_event).
411#[derive(Debug)]
412pub enum FromSwarm<'a, Handler> {
413    /// Informs the behaviour about a newly established connection to a peer.
414    ConnectionEstablished(ConnectionEstablished<'a>),
415    /// Informs the behaviour about a closed connection to a peer.
416    ///
417    /// This event is always paired with an earlier
418    /// [`FromSwarm::ConnectionEstablished`] with the same peer ID, connection ID
419    /// and endpoint.
420    ConnectionClosed(ConnectionClosed<'a, Handler>),
421    /// Informs the behaviour that the [`ConnectedPoint`] of an existing
422    /// connection has changed.
423    AddressChange(AddressChange<'a>),
424    /// Informs the behaviour that the dial to a known
425    /// or unknown node failed.
426    DialFailure(DialFailure<'a>),
427    /// Informs the behaviour that an error
428    /// happened on an incoming connection during its initial handshake.
429    ///
430    /// This can include, for example, an error during the handshake of the encryption layer, or the
431    /// connection unexpectedly closed.
432    ListenFailure(ListenFailure<'a>),
433    /// Informs the behaviour that a new listener was created.
434    NewListener(NewListener),
435    /// Informs the behaviour that we have started listening on a new multiaddr.
436    NewListenAddr(NewListenAddr<'a>),
437    /// Informs the behaviour that a multiaddr
438    /// we were listening on has expired,
439    /// which means that we are no longer listening on it.
440    ExpiredListenAddr(ExpiredListenAddr<'a>),
441    /// Informs the behaviour that a listener experienced an error.
442    ListenerError(ListenerError<'a>),
443    /// Informs the behaviour that a listener closed.
444    ListenerClosed(ListenerClosed<'a>),
445    /// Informs the behaviour that we have discovered a new candidate for an external address for us.
446    NewExternalAddrCandidate(NewExternalAddrCandidate<'a>),
447    /// Informs the behaviour that an external address of the local node was confirmed.
448    ExternalAddrConfirmed(ExternalAddrConfirmed<'a>),
449    /// Informs the behaviour that an external address of the local node expired, i.e. is no-longer confirmed.
450    ExternalAddrExpired(ExternalAddrExpired<'a>),
451}
452
453/// [`FromSwarm`] variant that informs the behaviour about a newly established connection to a peer.
454#[derive(Debug, Clone, Copy)]
455pub struct ConnectionEstablished<'a> {
456    pub peer_id: PeerId,
457    pub connection_id: ConnectionId,
458    pub endpoint: &'a ConnectedPoint,
459    pub failed_addresses: &'a [Multiaddr],
460    pub other_established: usize,
461}
462
463/// [`FromSwarm`] variant that informs the behaviour about a closed connection to a peer.
464///
465/// This event is always paired with an earlier
466/// [`FromSwarm::ConnectionEstablished`] with the same peer ID, connection ID
467/// and endpoint.
468#[derive(Debug)]
469pub struct ConnectionClosed<'a, Handler> {
470    pub peer_id: PeerId,
471    pub connection_id: ConnectionId,
472    pub endpoint: &'a ConnectedPoint,
473    pub handler: Handler,
474    pub remaining_established: usize,
475}
476
477/// [`FromSwarm`] variant that informs the behaviour that the [`ConnectedPoint`] of an existing
478/// connection has changed.
479#[derive(Debug, Clone, Copy)]
480pub struct AddressChange<'a> {
481    pub peer_id: PeerId,
482    pub connection_id: ConnectionId,
483    pub old: &'a ConnectedPoint,
484    pub new: &'a ConnectedPoint,
485}
486
487/// [`FromSwarm`] variant that informs the behaviour that the dial to a known
488/// or unknown node failed.
489#[derive(Debug, Clone, Copy)]
490pub struct DialFailure<'a> {
491    pub peer_id: Option<PeerId>,
492    pub error: &'a DialError,
493    pub connection_id: ConnectionId,
494}
495
496/// [`FromSwarm`] variant that informs the behaviour that an error
497/// happened on an incoming connection during its initial handshake.
498///
499/// This can include, for example, an error during the handshake of the encryption layer, or the
500/// connection unexpectedly closed.
501#[derive(Debug, Clone, Copy)]
502pub struct ListenFailure<'a> {
503    pub local_addr: &'a Multiaddr,
504    pub send_back_addr: &'a Multiaddr,
505    pub error: &'a ListenError,
506    pub connection_id: ConnectionId,
507}
508
509/// [`FromSwarm`] variant that informs the behaviour that a new listener was created.
510#[derive(Debug, Clone, Copy)]
511pub struct NewListener {
512    pub listener_id: ListenerId,
513}
514
515/// [`FromSwarm`] variant that informs the behaviour
516/// that we have started listening on a new multiaddr.
517#[derive(Debug, Clone, Copy)]
518pub struct NewListenAddr<'a> {
519    pub listener_id: ListenerId,
520    pub addr: &'a Multiaddr,
521}
522
523/// [`FromSwarm`] variant that informs the behaviour that a multiaddr
524/// we were listening on has expired,
525/// which means that we are no longer listening on it.
526#[derive(Debug, Clone, Copy)]
527pub struct ExpiredListenAddr<'a> {
528    pub listener_id: ListenerId,
529    pub addr: &'a Multiaddr,
530}
531
532/// [`FromSwarm`] variant that informs the behaviour that a listener experienced an error.
533#[derive(Debug, Clone, Copy)]
534pub struct ListenerError<'a> {
535    pub listener_id: ListenerId,
536    pub err: &'a (dyn std::error::Error + 'static),
537}
538
539/// [`FromSwarm`] variant that informs the behaviour that a listener closed.
540#[derive(Debug, Clone, Copy)]
541pub struct ListenerClosed<'a> {
542    pub listener_id: ListenerId,
543    pub reason: Result<(), &'a std::io::Error>,
544}
545
546/// [`FromSwarm`] variant that informs the behaviour about a new candidate for an external address for us.
547#[derive(Debug, Clone, Copy)]
548pub struct NewExternalAddrCandidate<'a> {
549    pub addr: &'a Multiaddr,
550}
551
552/// [`FromSwarm`] variant that informs the behaviour that an external address was confirmed.
553#[derive(Debug, Clone, Copy)]
554pub struct ExternalAddrConfirmed<'a> {
555    pub addr: &'a Multiaddr,
556}
557
558/// [`FromSwarm`] variant that informs the behaviour that an external address was removed.
559#[derive(Debug, Clone, Copy)]
560pub struct ExternalAddrExpired<'a> {
561    pub addr: &'a Multiaddr,
562}
563
564impl<'a, Handler> FromSwarm<'a, Handler> {
565    fn map_handler<NewHandler>(
566        self,
567        map_handler: impl FnOnce(Handler) -> NewHandler,
568    ) -> FromSwarm<'a, NewHandler> {
569        self.maybe_map_handler(|h| Some(map_handler(h)))
570            .expect("To return Some as all closures return Some.")
571    }
572
573    fn maybe_map_handler<NewHandler>(
574        self,
575        map_handler: impl FnOnce(Handler) -> Option<NewHandler>,
576    ) -> Option<FromSwarm<'a, NewHandler>> {
577        match self {
578            FromSwarm::ConnectionClosed(ConnectionClosed {
579                peer_id,
580                connection_id,
581                endpoint,
582                handler,
583                remaining_established,
584            }) => Some(FromSwarm::ConnectionClosed(ConnectionClosed {
585                peer_id,
586                connection_id,
587                endpoint,
588                handler: map_handler(handler)?,
589                remaining_established,
590            })),
591            FromSwarm::ConnectionEstablished(ConnectionEstablished {
592                peer_id,
593                connection_id,
594                endpoint,
595                failed_addresses,
596                other_established,
597            }) => Some(FromSwarm::ConnectionEstablished(ConnectionEstablished {
598                peer_id,
599                connection_id,
600                endpoint,
601                failed_addresses,
602                other_established,
603            })),
604            FromSwarm::AddressChange(AddressChange {
605                peer_id,
606                connection_id,
607                old,
608                new,
609            }) => Some(FromSwarm::AddressChange(AddressChange {
610                peer_id,
611                connection_id,
612                old,
613                new,
614            })),
615            FromSwarm::DialFailure(DialFailure {
616                peer_id,
617                error,
618                connection_id,
619            }) => Some(FromSwarm::DialFailure(DialFailure {
620                peer_id,
621                error,
622                connection_id,
623            })),
624            FromSwarm::ListenFailure(ListenFailure {
625                local_addr,
626                send_back_addr,
627                connection_id,
628                error,
629            }) => Some(FromSwarm::ListenFailure(ListenFailure {
630                local_addr,
631                send_back_addr,
632                connection_id,
633                error,
634            })),
635            FromSwarm::NewListener(NewListener { listener_id }) => {
636                Some(FromSwarm::NewListener(NewListener { listener_id }))
637            }
638            FromSwarm::NewListenAddr(NewListenAddr { listener_id, addr }) => {
639                Some(FromSwarm::NewListenAddr(NewListenAddr {
640                    listener_id,
641                    addr,
642                }))
643            }
644            FromSwarm::ExpiredListenAddr(ExpiredListenAddr { listener_id, addr }) => {
645                Some(FromSwarm::ExpiredListenAddr(ExpiredListenAddr {
646                    listener_id,
647                    addr,
648                }))
649            }
650            FromSwarm::ListenerError(ListenerError { listener_id, err }) => {
651                Some(FromSwarm::ListenerError(ListenerError { listener_id, err }))
652            }
653            FromSwarm::ListenerClosed(ListenerClosed {
654                listener_id,
655                reason,
656            }) => Some(FromSwarm::ListenerClosed(ListenerClosed {
657                listener_id,
658                reason,
659            })),
660            FromSwarm::NewExternalAddrCandidate(e) => Some(FromSwarm::NewExternalAddrCandidate(e)),
661            FromSwarm::ExternalAddrExpired(e) => Some(FromSwarm::ExternalAddrExpired(e)),
662            FromSwarm::ExternalAddrConfirmed(e) => Some(FromSwarm::ExternalAddrConfirmed(e)),
663        }
664    }
665}