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}