1use std::{
2 collections::{HashMap, HashSet, VecDeque},
3 convert::Infallible,
4 io,
5 task::{Context, Poll},
6 time::Duration,
7};
8
9use either::Either;
10use futures::{StreamExt, channel::mpsc};
11use volans_core::{Multiaddr, PeerId};
12use volans_swarm::{
13 BehaviorEvent, ConnectionDenied, ConnectionId, DialOpts, NetworkBehavior,
14 NetworkOutgoingBehavior, PeerCondition, THandlerAction, THandlerEvent,
15 behavior::NotifyHandler,
16 error::{ConnectionError, DialError},
17 handler::DummyHandler,
18};
19
20use crate::{MultiaddrExt, transport::TransportRequest};
21
22use super::handler;
23pub struct Behavior {
24 transport_receiver: mpsc::Receiver<TransportRequest>,
25 direct_connections: HashMap<PeerId, HashSet<ConnectionId>>,
26 pending_channels: HashMap<PeerId, VecDeque<handler::NewOutboundBridgeRequest>>,
27 dial_peers: VecDeque<(PeerId, Option<Multiaddr>)>,
28 pending_events: VecDeque<BehaviorEvent<Infallible, THandlerAction<Self>>>,
29 timeout: Duration,
30}
31
32impl Behavior {
33 pub fn new(transport_receiver: mpsc::Receiver<TransportRequest>) -> Self {
34 Self {
35 transport_receiver,
36 direct_connections: HashMap::new(),
37 pending_channels: HashMap::new(),
38 dial_peers: VecDeque::new(),
39 pending_events: VecDeque::new(),
40 timeout: Duration::from_secs(15), }
42 }
43}
44
45impl NetworkBehavior for Behavior {
46 type ConnectionHandler = Either<DummyHandler, handler::Handler>;
47 type Event = Infallible;
48
49 fn on_connection_handler_event(
50 &mut self,
51 _id: ConnectionId,
52 _peer_id: PeerId,
53 _event: THandlerEvent<Self>,
54 ) {
55 unreachable!("This behavior does not handle connection events directly.");
56 }
57
58 fn poll(
59 &mut self,
60 cx: &mut Context<'_>,
61 ) -> Poll<BehaviorEvent<Self::Event, THandlerAction<Self>>> {
62 loop {
63 if let Some(event) = self.pending_events.pop_front() {
64 return Poll::Ready(event);
65 }
66 match self.transport_receiver.poll_next_unpin(cx) {
67 Poll::Ready(Some(TransportRequest::DialRequest {
68 relay_addr,
69 relay_peer_id,
70 dst_peer_id,
71 send_back,
72 })) => {
73 let connection_id = self
74 .direct_connections
75 .get(&relay_peer_id)
76 .and_then(|set| set.iter().next())
77 .cloned();
78
79 if let Some(connection_id) = connection_id {
80 tracing::debug!(
81 "Sending request to relay peer: {:?}, connection ID: {:?}",
82 relay_peer_id,
83 connection_id
84 );
85 return Poll::Ready(BehaviorEvent::HandlerAction {
86 peer_id: relay_peer_id,
87 handler: NotifyHandler::One(connection_id),
88 action: Either::Right(handler::NewOutboundBridgeRequest {
89 _dst_addresses: vec![],
90 dst_peer_id,
91 send_back,
92 }),
93 });
94 } else {
95 tracing::debug!(
96 "No direct connection to relay peer: {:?}, attempting to dial",
97 relay_peer_id
98 );
99 self.pending_channels
100 .entry(relay_peer_id)
101 .or_default()
102 .push_back(handler::NewOutboundBridgeRequest {
103 _dst_addresses: vec![],
104 dst_peer_id,
105 send_back,
106 });
107 self.dial_peers.push_back((relay_peer_id, Some(relay_addr)));
108 continue;
109 }
110 }
111 Poll::Ready(Some(TransportRequest::ListenRequest { .. })) => {
112 tracing::error!("Unexpected ListenRequest in Behavior");
113 }
114 Poll::Pending | Poll::Ready(None) => {}
115 }
116 return Poll::Pending;
117 }
118 }
119}
120
121impl NetworkOutgoingBehavior for Behavior {
122 fn handle_established_connection(
123 &mut self,
124 _id: ConnectionId,
125 _peer_id: PeerId,
126 addr: &Multiaddr,
127 ) -> Result<Self::ConnectionHandler, ConnectionDenied> {
128 if !addr.is_circuit() {
129 Ok(Either::Right(handler::Handler::new(self.timeout)))
131 } else {
132 Ok(Either::Left(DummyHandler))
134 }
135 }
136
137 fn on_connection_established(&mut self, id: ConnectionId, peer_id: PeerId, addr: &Multiaddr) {
138 tracing::warn!(
140 "Connection established with peer: {:?}, addr: {:?}",
141 peer_id,
142 addr
143 );
144
145 if !addr.is_circuit() {
146 self.direct_connections
147 .entry(peer_id)
148 .or_default()
149 .insert(id);
150
151 if let Some(mut requests) = self.pending_channels.remove(&peer_id) {
153 while let Some(request) = requests.pop_front() {
154 let connection_id = self
155 .direct_connections
156 .get(&peer_id)
157 .and_then(|set| set.iter().next())
158 .cloned()
159 .expect("Connection ID should exist after connection established");
160 self.pending_events.push_back(BehaviorEvent::HandlerAction {
161 peer_id,
162 handler: NotifyHandler::One(connection_id),
163 action: Either::Right(request),
164 });
165 }
166 }
167 }
168 }
169
170 fn on_connection_closed(
171 &mut self,
172 id: ConnectionId,
173 peer_id: PeerId,
174 addr: &Multiaddr,
175 _reason: Option<&ConnectionError>,
176 ) {
177 if !addr.is_circuit() {
178 if let Some(connections) = self.direct_connections.get_mut(&peer_id) {
179 connections.remove(&id);
180 if connections.is_empty() {
181 self.direct_connections.remove(&peer_id);
182 }
183 }
184 }
185 }
186
187 fn on_dial_failure(
188 &mut self,
189 _id: ConnectionId,
190 peer_id: Option<PeerId>,
191 addr: Option<&Multiaddr>,
192 error: &DialError,
193 ) {
194 tracing::warn!(
195 "Dial failure occurred peer id: {:?}, addr: {:?}, error: {:?}",
196 peer_id,
197 addr,
198 error,
199 );
200 if let Some(peer_id) = peer_id {
201 if let Some(requests) = self.pending_channels.get_mut(&peer_id) {
202 if let Some(request) = requests.pop_front() {
203 tracing::error!("Dial failed for request: {:?}", request);
204 let _ = request.send_back.send(Err(io::Error::new(
205 io::ErrorKind::Other,
206 "Dial failed",
207 )
208 .into()));
209 }
210 }
211 }
212 }
213
214 fn poll_dial(&mut self, _cx: &mut Context<'_>) -> Poll<DialOpts> {
215 if let Some((peer, relay_addr)) = self.dial_peers.pop_front() {
216 tracing::debug!("Dialing Bridge peer: {:?}", peer);
217 return Poll::Ready(
218 DialOpts::new(relay_addr, Some(peer))
219 .with_condition(PeerCondition::DisconnectedAndNotDialing),
220 );
221 }
222 Poll::Pending
223 }
224}