communication/behaviour/
types.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use core::fmt::Debug;
5use libp2p::{
6    core::{Multiaddr, PeerId},
7    identify::{IdentifyEvent, IdentifyInfo},
8    identity::PublicKey,
9    request_response::{InboundFailure, OutboundFailure, RequestId, RequestResponseEvent, RequestResponseMessage},
10    swarm::ProtocolsHandlerUpgrErr,
11};
12
13#[cfg(feature = "mdns")]
14use libp2p::mdns::MdnsEvent;
15
16/// Event that can be produced by the `Mdns` behaviour.
17#[derive(Debug, Clone, PartialEq)]
18pub enum P2PMdnsEvent {
19    /// Discovered nodes through mDNS.
20    Discovered(Vec<(PeerId, Multiaddr)>),
21    /// Each discovered record has a time-to-live. When this TTL expires and the address hasn't
22    /// been refreshed, it is removed from the list and emit it as an `Expired` event.
23    Expired(Vec<(PeerId, Multiaddr)>),
24}
25
26/// Information of a peer sent in `Identify` protocol responses.
27#[derive(Debug, Clone, PartialEq)]
28pub struct P2PIdentifyInfo {
29    /// The public key underlying the peer's `PeerId`.
30    pub public_key: PublicKey,
31    /// Version of the protocol family used by the peer, e.g. `p2p/1.0.0`
32    pub protocol_version: String,
33    /// Name and version of the peer, similar to the `User-Agent` header in
34    /// the HTTP protocol.
35    pub agent_version: String,
36    /// The addresses that the peer is listening on.
37    pub listen_addrs: Vec<Multiaddr>,
38    /// The list of protocols supported by the peer, e.g. `/p2p/ping/1.0.0`.
39    pub protocols: Vec<String>,
40    /// The address observed by the peer for the local node.
41    pub observed_addr: Multiaddr,
42}
43
44/// Error that can happen on an outbound substream opening attempt.
45#[derive(Debug, Clone, PartialEq)]
46pub enum P2PProtocolsHandlerUpgrErr {
47    /// The opening attempt timed out before the negotiation was fully completed.
48    Timeout,
49    /// There was an error in the timer used.
50    Timer,
51    /// Error while upgrading the substream to the protocol we want.
52    Upgrade,
53}
54
55/// Event emitted  by the `Identify` behaviour.
56#[derive(Debug, Clone, PartialEq)]
57pub enum P2PIdentifyEvent {
58    /// Identifying information has been received from a peer.
59    Received { peer_id: PeerId, info: P2PIdentifyInfo },
60    /// Identifying information of the local node has been sent to a peer.
61    Sent { peer_id: PeerId },
62    /// Identification information of the local node has been actively pushed to
63    /// a peer.
64    Pushed {
65        /// The peer that the information has been sent to.
66        peer_id: PeerId,
67    },
68    /// Error while attempting to identify the remote.
69    Error {
70        peer_id: PeerId,
71        error: P2PProtocolsHandlerUpgrErr,
72    },
73}
74/// Possible failures occurring in the context of sending
75/// an outbound request and receiving the response.
76#[derive(Debug, Clone, PartialEq)]
77pub enum P2POutboundFailure {
78    /// The request could not be sent because a dialing attempt failed.
79    DialFailure,
80    /// The request timed out before a response was received.
81    ///
82    /// It is not known whether the request may have been
83    /// received (and processed) by the remote peer.
84    Timeout,
85    /// The connection closed before a response was received.
86    ///
87    /// It is not known whether the request may have been
88    /// received (and processed) by the remote peer.
89    ConnectionClosed,
90    /// The remote supports none of the requested protocols.
91    UnsupportedProtocols,
92}
93
94/// Possible failures occurring in the context of receiving an
95/// inbound request and sending a response.
96#[derive(Debug, Clone, PartialEq)]
97pub enum P2PInboundFailure {
98    /// The inbound request timed out, either while reading the
99    /// incoming request or before a response is sent
100    Timeout,
101    /// The local peer supports none of the requested protocols.
102    UnsupportedProtocols,
103    /// The local peer failed to respond to an inbound request
104    /// due to the [`ResponseChannel`] being dropped instead of
105    /// being passed to [`RequestResponse::send_response`].
106    ResponseOmission,
107    /// The connection closed before a response could be send.
108    ConnectionClosed,
109}
110
111/// Event emitted  by the `RequestResponse` behaviour.
112#[derive(Debug, Clone, PartialEq)]
113pub enum P2PReqResEvent<Req, Res> {
114    /// Request Message
115    ///
116    /// Requests require a response to acknowledge them, if [`P2PNetworkBehaviour::send_response`]
117    /// is not called in a timely manner, the protocol issues an
118    /// `InboundFailure` at the local node and an `OutboundFailure` at the remote.
119    Req {
120        peer_id: PeerId,
121        request_id: RequestId,
122        request: Req,
123    },
124    /// Response Message to a received `Req`.
125    ///
126    /// The `ResponseChannel` for the request is stored by the `P2PNetworkBehaviour` in
127    /// a Hashmap and identified by the  `request_id` that can be used to send the response.
128    /// If the `ResponseChannel` for the `request_id`is already closed
129    /// due to a timeout, the response is discarded and eventually
130    /// [`RequestResponseEvent::InboundFailure`] is emitted.
131    Res {
132        peer_id: PeerId,
133        request_id: RequestId,
134        response: Res,
135    },
136    InboundFailure {
137        peer_id: PeerId,
138        request_id: RequestId,
139        error: P2PInboundFailure,
140    },
141    OutboundFailure {
142        peer_id: PeerId,
143        request_id: RequestId,
144        error: P2POutboundFailure,
145    },
146    /// A response to an inbound request has been sent.
147    ///
148    /// When this event is received, the response has been flushed on the underlying transport connection.
149    ResSent { peer_id: PeerId, request_id: RequestId },
150}
151
152/// Event that was emitted by one of the protocols of the `P2PNetworkBehaviour`
153#[derive(Debug, Clone, PartialEq)]
154pub enum P2PEvent<Req, Res> {
155    /// Events from the libp2p mDNS protocol
156    Mdns(P2PMdnsEvent),
157    /// Events from the libp2p identify protocol
158    Identify(Box<P2PIdentifyEvent>),
159    /// Events from the custom request-response protocol
160    RequestResponse(Box<P2PReqResEvent<Req, Res>>),
161}
162
163#[cfg(feature = "mdns")]
164impl<Req, Res> From<MdnsEvent> for P2PEvent<Req, Res> {
165    fn from(event: MdnsEvent) -> P2PEvent<Req, Res> {
166        match event {
167            MdnsEvent::Discovered(list) => P2PEvent::Mdns(P2PMdnsEvent::Discovered(list.collect())),
168            MdnsEvent::Expired(list) => P2PEvent::Mdns(P2PMdnsEvent::Expired(list.collect())),
169        }
170    }
171}
172
173impl<Req, Res> From<IdentifyEvent> for P2PEvent<Req, Res> {
174    fn from(event: IdentifyEvent) -> P2PEvent<Req, Res> {
175        match event {
176            IdentifyEvent::Received {
177                peer_id,
178                info:
179                    IdentifyInfo {
180                        public_key,
181                        protocol_version,
182                        agent_version,
183                        listen_addrs,
184                        protocols,
185                        observed_addr,
186                    },
187            } => P2PEvent::Identify(Box::new(P2PIdentifyEvent::Received {
188                peer_id,
189                info: P2PIdentifyInfo {
190                    public_key,
191                    protocol_version,
192                    agent_version,
193                    listen_addrs,
194                    protocols,
195                    observed_addr,
196                },
197            })),
198            IdentifyEvent::Sent { peer_id } => P2PEvent::Identify(Box::new(P2PIdentifyEvent::Sent { peer_id })),
199            IdentifyEvent::Pushed { peer_id } => P2PEvent::Identify(Box::new(P2PIdentifyEvent::Pushed { peer_id })),
200            IdentifyEvent::Error { peer_id, error } => {
201                let error = match error {
202                    ProtocolsHandlerUpgrErr::Timeout => P2PProtocolsHandlerUpgrErr::Timeout,
203                    ProtocolsHandlerUpgrErr::Timer => P2PProtocolsHandlerUpgrErr::Timer,
204                    ProtocolsHandlerUpgrErr::Upgrade(_) => P2PProtocolsHandlerUpgrErr::Upgrade,
205                };
206                P2PEvent::Identify(Box::new(P2PIdentifyEvent::Error { peer_id, error }))
207            }
208        }
209    }
210}
211
212impl<Req, Res> From<RequestResponseEvent<Req, Res>> for P2PEvent<Req, Res> {
213    fn from(event: RequestResponseEvent<Req, Res>) -> P2PEvent<Req, Res> {
214        match event {
215            RequestResponseEvent::Message { peer, message } => match message {
216                RequestResponseMessage::Request {
217                    request_id, request, ..
218                } => P2PEvent::RequestResponse(Box::new(P2PReqResEvent::Req {
219                    peer_id: peer,
220                    request_id,
221                    request,
222                })),
223                RequestResponseMessage::Response { request_id, response } => {
224                    P2PEvent::RequestResponse(Box::new(P2PReqResEvent::Res {
225                        peer_id: peer,
226                        request_id,
227                        response,
228                    }))
229                }
230            },
231            RequestResponseEvent::OutboundFailure {
232                peer,
233                request_id,
234                error,
235            } => {
236                let error = match error {
237                    OutboundFailure::DialFailure => P2POutboundFailure::DialFailure,
238                    OutboundFailure::Timeout => P2POutboundFailure::Timeout,
239                    OutboundFailure::ConnectionClosed => P2POutboundFailure::ConnectionClosed,
240                    OutboundFailure::UnsupportedProtocols => P2POutboundFailure::UnsupportedProtocols,
241                };
242                P2PEvent::RequestResponse(Box::new(P2PReqResEvent::OutboundFailure {
243                    peer_id: peer,
244                    request_id,
245                    error,
246                }))
247            }
248            RequestResponseEvent::InboundFailure {
249                peer,
250                request_id,
251                error,
252            } => {
253                let error = match error {
254                    InboundFailure::Timeout => P2PInboundFailure::Timeout,
255                    InboundFailure::ResponseOmission => P2PInboundFailure::ResponseOmission,
256                    InboundFailure::UnsupportedProtocols => P2PInboundFailure::UnsupportedProtocols,
257                    InboundFailure::ConnectionClosed => P2PInboundFailure::ConnectionClosed,
258                };
259                P2PEvent::RequestResponse(Box::new(P2PReqResEvent::InboundFailure {
260                    peer_id: peer,
261                    request_id,
262                    error,
263                }))
264            }
265            RequestResponseEvent::ResponseSent { peer, request_id } => {
266                P2PEvent::RequestResponse(Box::new(P2PReqResEvent::ResSent {
267                    peer_id: peer,
268                    request_id,
269                }))
270            }
271        }
272    }
273}