Skip to main content

volans_bridge/client/
behavior.rs

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), // Default timeout for outbound requests
41        }
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            // 如果是待处理的请求,返回对应的处理器
130            Ok(Either::Right(handler::Handler::new(self.timeout)))
131        } else {
132            // 否则返回一个空的处理器
133            Ok(Either::Left(DummyHandler))
134        }
135    }
136
137    fn on_connection_established(&mut self, id: ConnectionId, peer_id: PeerId, addr: &Multiaddr) {
138        // 在排队中的连接
139        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            // 处理拨号成功,移出正在排队的请求
152            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}