Skip to main content

volans_swarm/connection/
pool.rs

1mod task;
2
3use std::{
4    collections::HashMap,
5    convert::Infallible,
6    io,
7    task::{Context, Poll, Waker},
8    time::{Duration, Instant},
9};
10
11use fnv::{FnvHashMap, FnvHashSet};
12use futures::{
13    StreamExt,
14    channel::{mpsc, oneshot},
15    stream::{FuturesUnordered, SelectAll},
16};
17use tracing::Instrument;
18use volans_core::{
19    ConnectedPoint, Multiaddr, PeerId,
20    muxing::{StreamMuxerBox, StreamMuxerExt},
21};
22
23use crate::{
24    ConnectionHandler, ConnectionId, ExecSwitch, Executor, InboundStreamHandler,
25    OutboundStreamHandler,
26    connection::{InboundConnection, OutboundConnection},
27    error::{ConnectionError, PendingConnectionError},
28};
29
30/// 连接池
31/// 管理连接的建立、维护和事件处理
32///
33/// 状态机
34/// add_incoming -> pending -> Event::ConnectionEstablished -> spawn_connection -> established
35/// add_outgoing -> pending -> Event::ConnectionEstablished -> spawn_connection -> established
36
37pub struct Pool<THandler>
38where
39    THandler: ConnectionHandler,
40{
41    local_id: PeerId,
42
43    /// 等待中的连接
44    pending: HashMap<ConnectionId, PendingConnection>,
45    pending_peer_connections: FnvHashMap<PeerId, FnvHashSet<ConnectionId>>,
46
47    established: FnvHashMap<ConnectionId, EstablishedConnection<THandler::Action>>,
48
49    /// 已建立的连接
50    established_peer_connections: FnvHashMap<PeerId, FnvHashSet<ConnectionId>>,
51
52    executor: ExecSwitch,
53
54    /// 等待中的连接事件 Sender
55    pending_connection_events_tx: mpsc::Sender<task::PendingConnectionEvent>,
56
57    /// 等待中的连接事件 Receiver
58    pending_connection_events_rx: mpsc::Receiver<task::PendingConnectionEvent>,
59
60    /// 没有建立连接的唤醒器
61    no_established_connections_waker: Option<Waker>,
62
63    established_connection_events:
64        SelectAll<mpsc::Receiver<task::EstablishedConnectionEvent<THandler::Event>>>,
65
66    /// 新连接丢弃监听器
67    new_connection_dropped_listeners: FuturesUnordered<oneshot::Receiver<StreamMuxerBox>>,
68
69    /// 任务命令缓冲区大小
70    task_command_buffer_size: usize,
71    /// 最大协商入站流数量
72    max_negotiating_inbound_streams: usize,
73    /// 每个连接事件缓冲区大小
74    per_connection_event_buffer_size: usize,
75    /// 连接空闲超时
76    idle_connection_timeout: Duration,
77}
78
79impl<THandler> Pool<THandler>
80where
81    THandler: ConnectionHandler,
82{
83    pub fn new(local_id: PeerId, config: PoolConfig) -> Self {
84        let (pending_connection_events_tx, pending_connection_events_rx) = mpsc::channel(0);
85
86        Pool {
87            local_id,
88            pending: HashMap::new(),
89            pending_peer_connections: FnvHashMap::default(),
90            established: FnvHashMap::default(),
91            established_peer_connections: FnvHashMap::default(),
92            executor: ExecSwitch::new(config.executor),
93            pending_connection_events_tx,
94            pending_connection_events_rx,
95            no_established_connections_waker: None,
96            established_connection_events: SelectAll::new(),
97            new_connection_dropped_listeners: FuturesUnordered::new(),
98            task_command_buffer_size: config.task_command_buffer_size,
99            max_negotiating_inbound_streams: config.max_negotiating_inbound_streams,
100            per_connection_event_buffer_size: config.per_connection_event_buffer_size,
101            idle_connection_timeout: config.idle_connection_timeout,
102        }
103    }
104
105    pub fn disconnect(&mut self, id: &PeerId) {
106        //处理 Pending 的连接:1、Remove Pending Map;2、中断连接任务
107        for connection in self
108            .pending_peer_connections
109            .remove(id)
110            .into_iter()
111            .flatten()
112        {
113            if let Some(mut pending) = self.pending.remove(&connection) {
114                pending.abort();
115            }
116        }
117        //处理已建立的连接: 给所有连接发送关闭命令
118        if let Some(connections) = self.established_peer_connections.get(id) {
119            for connection in connections.iter() {
120                if let Some(established) = self.established.get_mut(&connection) {
121                    established.start_close();
122                }
123            }
124        }
125    }
126
127    pub(crate) fn get_established(
128        &mut self,
129        id: ConnectionId,
130    ) -> Option<&mut EstablishedConnection<THandler::Action>> {
131        self.established.get_mut(&id)
132    }
133
134    pub(crate) fn is_peer_connected(&self, id: &PeerId) -> bool {
135        self.established_peer_connections.contains_key(id)
136    }
137
138    pub(crate) fn is_peer_dialing(&self, id: &PeerId) -> bool {
139        if let Some(connections) = self.pending_peer_connections.get(id) {
140            for connection in connections.iter() {
141                if let Some(pending) = self.pending.get(connection) {
142                    if matches!(pending.endpoint, ConnectedPoint::Dialer { .. }) {
143                        return true;
144                    }
145                }
146            }
147        }
148        return false;
149    }
150
151    pub fn iter_established_connections_of_peer(
152        &mut self,
153        peer_id: &PeerId,
154    ) -> impl Iterator<Item = ConnectionId> + '_ {
155        match self.established_peer_connections.get(peer_id) {
156            Some(conns) => either::Either::Left(conns.iter().copied()),
157            None => either::Either::Right(std::iter::empty()),
158        }
159    }
160
161    pub fn num_peer_established(&self, peer_id: &PeerId) -> usize {
162        self.established_peer_connections
163            .get(peer_id)
164            .map_or(0, |conns| conns.len())
165    }
166
167    pub(crate) fn iter_peer_connected(&self) -> impl Iterator<Item = &PeerId> {
168        self.established_peer_connections.keys()
169    }
170
171    pub(crate) fn iter_connected(&self) -> impl Iterator<Item = &ConnectionId> {
172        self.established.keys()
173    }
174
175    pub fn add_outgoing<TFut>(
176        &mut self,
177        id: ConnectionId,
178        future: TFut,
179        addr: Multiaddr,
180        peer_id: Option<PeerId>,
181    ) where
182        TFut: Future<Output = Result<(PeerId, StreamMuxerBox), io::Error>> + Send + 'static,
183    {
184        let (abort_notifier, abort_receiver) = oneshot::channel();
185        let span = tracing::debug_span!(parent: tracing::Span::none(), "new_outgoing_connection", id = %id, peer_id = ?peer_id, remote_addr = %addr);
186        span.follows_from(tracing::Span::current());
187        self.executor.spawn(
188            task::new_for_pending_connection(
189                id,
190                addr.clone(),
191                future,
192                abort_receiver,
193                self.pending_connection_events_tx.clone(),
194            )
195            .instrument(span),
196        );
197        if let Some(peer_id) = peer_id {
198            self.pending_peer_connections
199                .entry(peer_id)
200                .or_default()
201                .insert(id);
202        }
203        self.pending.insert(
204            id,
205            PendingConnection {
206                peer_id,
207                endpoint: ConnectedPoint::Dialer { addr },
208                abort_notifier: Some(abort_notifier),
209                accepted_at: Instant::now(),
210            },
211        );
212    }
213
214    pub fn add_incoming<TFut>(
215        &mut self,
216        id: ConnectionId,
217        future: TFut,
218        local_addr: Multiaddr,
219        remote_addr: Multiaddr,
220    ) where
221        TFut: Future<Output = Result<(PeerId, StreamMuxerBox), io::Error>> + Send + 'static,
222    {
223        let (abort_notifier, abort_receiver) = oneshot::channel();
224        let span = tracing::debug_span!(parent: tracing::Span::none(), "new_incoming_connection", id = %id, local_addr = %local_addr, remote_addr = %remote_addr);
225        span.follows_from(tracing::Span::current());
226        self.executor.spawn(
227            task::new_for_pending_connection(
228                id,
229                remote_addr.clone(),
230                future,
231                abort_receiver,
232                self.pending_connection_events_tx.clone(),
233            )
234            .instrument(span),
235        );
236        self.pending.insert(
237            id,
238            PendingConnection {
239                peer_id: None,
240                endpoint: ConnectedPoint::Listener {
241                    local_addr,
242                    remote_addr,
243                },
244                abort_notifier: Some(abort_notifier),
245                accepted_at: Instant::now(),
246            },
247        );
248    }
249
250    pub fn spawn_inbound_connection(
251        &mut self,
252        id: ConnectionId,
253        obtained_peer_id: PeerId,
254        endpoint: ConnectedPoint,
255        connection: NewConnection,
256        handler: THandler,
257    ) where
258        THandler: InboundStreamHandler,
259    {
260        let muxer = connection.extract();
261        let established_peer_connections = self
262            .established_peer_connections
263            .entry(obtained_peer_id)
264            .or_default();
265
266        let (command_tx, command_rx) = mpsc::channel(self.task_command_buffer_size);
267        let (event_tx, event_rx) = mpsc::channel(self.per_connection_event_buffer_size);
268        // 创建连接处理器
269        self.established.insert(
270            id,
271            EstablishedConnection {
272                endpoint,
273                sender: command_tx,
274            },
275        );
276        // 将连接 ID 添加到已建立的连接列表
277        established_peer_connections.insert(id);
278        self.established_connection_events.push(event_rx);
279        if let Some(waker) = Option::take(&mut self.no_established_connections_waker) {
280            waker.wake();
281        }
282        let span = tracing::debug_span!(parent: tracing::Span::none(), "new_inbound_established", %id, peer = %obtained_peer_id);
283        span.follows_from(tracing::Span::current());
284        let connection = InboundConnection::new(
285            muxer,
286            handler,
287            self.max_negotiating_inbound_streams,
288            self.idle_connection_timeout,
289        );
290        self.executor.spawn(
291            task::new_for_established_connection(
292                id,
293                obtained_peer_id,
294                connection,
295                command_rx,
296                event_tx,
297            )
298            .instrument(span),
299        );
300    }
301
302    pub fn spawn_outbound_connection(
303        &mut self,
304        id: ConnectionId,
305        obtained_peer_id: PeerId,
306        endpoint: ConnectedPoint,
307        connection: NewConnection,
308        handler: THandler,
309    ) where
310        THandler: OutboundStreamHandler,
311    {
312        let muxer = connection.extract();
313        let established_peer_connections = self
314            .established_peer_connections
315            .entry(obtained_peer_id)
316            .or_default();
317
318        let (command_tx, command_rx) = mpsc::channel(self.task_command_buffer_size);
319        let (event_tx, event_rx) = mpsc::channel(self.per_connection_event_buffer_size);
320        // 创建连接处理器
321        self.established.insert(
322            id,
323            EstablishedConnection {
324                endpoint,
325                sender: command_tx,
326            },
327        );
328        // 将连接 ID 添加到已建立的连接列表
329        established_peer_connections.insert(id);
330        self.established_connection_events.push(event_rx);
331        if let Some(waker) = Option::take(&mut self.no_established_connections_waker) {
332            waker.wake();
333        }
334        let span = tracing::debug_span!(parent: tracing::Span::none(), "new_outbound_established", %id, peer = %obtained_peer_id);
335        span.follows_from(tracing::Span::current());
336        let connection = OutboundConnection::new(muxer, handler, self.idle_connection_timeout);
337        self.executor.spawn(
338            task::new_for_established_connection(
339                id,
340                obtained_peer_id,
341                connection,
342                command_rx,
343                event_tx,
344            )
345            .instrument(span),
346        );
347    }
348
349    #[tracing::instrument(level = "debug", name = "Pool::poll", skip(self, cx))]
350    pub fn poll(&mut self, cx: &mut Context<'_>) -> Poll<PoolEvent<THandler::Event>> {
351        match self.established_connection_events.poll_next_unpin(cx) {
352            Poll::Pending => {}
353            Poll::Ready(None) => {
354                // 如果没有更多的连接事件,设置唤醒器
355                self.no_established_connections_waker = Some(cx.waker().clone());
356            }
357            Poll::Ready(Some(task::EstablishedConnectionEvent::Notify { id, peer_id, event })) => {
358                return Poll::Ready(PoolEvent::ConnectionEvent { id, peer_id, event });
359            }
360            Poll::Ready(Some(task::EstablishedConnectionEvent::Closed { id, peer_id, error })) => {
361                if let Some(connections) = self.established_peer_connections.get_mut(&peer_id) {
362                    connections.remove(&id);
363                    if connections.is_empty() {
364                        self.established_peer_connections.remove(&peer_id);
365                    }
366                }
367                let EstablishedConnection { endpoint, .. } = self
368                    .established
369                    .remove(&id)
370                    .expect("Connection should be established before being closed");
371
372                let num_remaining_established = self
373                    .established_peer_connections
374                    .get(&peer_id)
375                    .map_or(0, |conns| conns.len());
376
377                return Poll::Ready(PoolEvent::ConnectionClosed {
378                    id,
379                    peer_id,
380                    endpoint,
381                    num_remaining_established,
382                    error,
383                });
384            }
385        }
386        loop {
387            if let Poll::Ready(Some(result)) =
388                self.new_connection_dropped_listeners.poll_next_unpin(cx)
389            {
390                if let Ok(dropped_connection) = result {
391                    self.executor.spawn(async move {
392                        let _ = dropped_connection.close().await;
393                    });
394                }
395                continue;
396            }
397
398            let event = match self.pending_connection_events_rx.poll_next_unpin(cx) {
399                Poll::Ready(Some(event)) => event,
400                Poll::Pending => return Poll::Pending,
401                Poll::Ready(None) => unreachable!("Pool holds both sender and receiver."),
402            };
403
404            let id = event.id();
405            let PendingConnection {
406                peer_id: expected_peer_id,
407                endpoint,
408                abort_notifier: _,
409                accepted_at,
410            } = self
411                .pending
412                .remove(&id)
413                .expect("Pending connection should exist before being established");
414
415            match event {
416                // 处理连接建立事件
417                task::PendingConnectionEvent::ConnectionEstablished {
418                    id,
419                    peer_id: obtained_peer_id,
420                    muxer,
421                } => {
422                    // 检查是否有预期的 PeerId
423                    if let Some(peer_id) = expected_peer_id {
424                        if peer_id != peer_id {
425                            let err_event = match &endpoint {
426                                ConnectedPoint::Dialer { .. } => {
427                                    PoolEvent::PendingConnectionError {
428                                        id,
429                                        peer_id: Some(peer_id),
430                                        endpoint,
431                                        error: PendingConnectionError::WrongPeerId {
432                                            obtained: peer_id,
433                                        },
434                                    }
435                                }
436                                ConnectedPoint::Listener { .. } => unreachable!(
437                                    "Listener connections should not have peer ID mismatch"
438                                ),
439                            };
440                            return Poll::Ready(err_event);
441                        }
442                    }
443                    // 是否是本地回环
444                    if self.local_id == obtained_peer_id {
445                        let err_event = match &endpoint {
446                            ConnectedPoint::Dialer { .. } => PoolEvent::PendingConnectionError {
447                                id,
448                                peer_id: expected_peer_id,
449                                endpoint,
450                                error: PendingConnectionError::LocalPeerId,
451                            },
452                            ConnectedPoint::Listener { .. } => PoolEvent::PendingConnectionError {
453                                id,
454                                peer_id: expected_peer_id,
455                                endpoint,
456                                error: PendingConnectionError::LocalPeerId,
457                            },
458                        };
459                        return Poll::Ready(err_event);
460                    }
461                    let established_in = accepted_at.elapsed();
462
463                    let (connection, drop_listener) = NewConnection::new(muxer);
464                    self.new_connection_dropped_listeners.push(drop_listener);
465
466                    return Poll::Ready(PoolEvent::ConnectionEstablished {
467                        id,
468                        peer_id: obtained_peer_id,
469                        endpoint,
470                        connection,
471                        established_in,
472                    });
473                }
474                // 处理入站连接错误
475                task::PendingConnectionEvent::PendingFailed { id, error } => {
476                    return Poll::Ready(PoolEvent::PendingConnectionError {
477                        id,
478                        peer_id: expected_peer_id,
479                        endpoint,
480                        error,
481                    });
482                }
483            }
484        }
485    }
486}
487
488pub(crate) struct PendingConnection {
489    peer_id: Option<PeerId>,
490    endpoint: ConnectedPoint,
491    abort_notifier: Option<oneshot::Sender<Infallible>>,
492    accepted_at: Instant,
493}
494
495impl PendingConnection {
496    fn abort(&mut self) {
497        if let Some(notifier) = self.abort_notifier.take() {
498            drop(notifier);
499        }
500    }
501}
502
503#[derive(Debug)]
504pub struct EstablishedConnection<TAction> {
505    endpoint: ConnectedPoint,
506    sender: mpsc::Sender<task::Command<TAction>>,
507}
508
509impl<TAction> EstablishedConnection<TAction> {
510    pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
511        self.sender.poll_ready(cx).map_err(|_| ())
512    }
513
514    pub(crate) fn start_send(&mut self, action: TAction) -> Result<(), ()> {
515        self.sender
516            .start_send(task::Command::Action(action))
517            .map_err(|_| ())
518    }
519
520    pub(crate) fn start_close(&mut self) {
521        match self.sender.clone().try_send(task::Command::Close) {
522            Ok(()) => {}
523            Err(e) => assert!(e.is_disconnected(), "No capacity for close command."),
524        };
525    }
526}
527
528#[derive(Debug)]
529pub enum PoolEvent<TEvent> {
530    ConnectionEstablished {
531        id: ConnectionId,
532        peer_id: PeerId,
533        endpoint: ConnectedPoint,
534        connection: NewConnection,
535        established_in: Duration,
536    },
537
538    PendingConnectionError {
539        id: ConnectionId,
540        peer_id: Option<PeerId>,
541        endpoint: ConnectedPoint,
542        error: PendingConnectionError,
543    },
544
545    ConnectionClosed {
546        id: ConnectionId,
547        peer_id: PeerId,
548        endpoint: ConnectedPoint,
549        num_remaining_established: usize,
550        error: Option<ConnectionError>,
551    },
552    ConnectionEvent {
553        id: ConnectionId,
554        peer_id: PeerId,
555        event: TEvent,
556    },
557}
558
559#[derive(Debug)]
560pub struct NewConnection {
561    connection: Option<StreamMuxerBox>,
562    drop_sender: Option<oneshot::Sender<StreamMuxerBox>>,
563}
564
565impl NewConnection {
566    fn new(conn: StreamMuxerBox) -> (Self, oneshot::Receiver<StreamMuxerBox>) {
567        let (sender, receiver) = oneshot::channel();
568
569        (
570            Self {
571                connection: Some(conn),
572                drop_sender: Some(sender),
573            },
574            receiver,
575        )
576    }
577
578    fn extract(mut self) -> StreamMuxerBox {
579        self.connection
580            .take()
581            .expect("Connection should be available when extracted")
582    }
583}
584
585impl Drop for NewConnection {
586    fn drop(&mut self) {
587        if let Some(connection) = self.connection.take() {
588            let _ = self
589                .drop_sender
590                .take()
591                .expect("`drop_sender` to always be `Some`")
592                .send(connection);
593        }
594    }
595}
596
597pub struct PoolConfig {
598    executor: Box<dyn Executor + Send>,
599    task_command_buffer_size: usize,
600    per_connection_event_buffer_size: usize,
601    idle_connection_timeout: Duration,
602    max_negotiating_inbound_streams: usize,
603}
604
605impl PoolConfig {
606    pub fn new(executor: Box<dyn Executor + Send>) -> Self {
607        Self {
608            executor,
609            task_command_buffer_size: 32,
610            per_connection_event_buffer_size: 10,
611            idle_connection_timeout: Duration::from_secs(60),
612            max_negotiating_inbound_streams: 128,
613        }
614    }
615
616    pub fn with_task_command_buffer_size(mut self, size: usize) -> Self {
617        self.task_command_buffer_size = size;
618        self
619    }
620
621    pub fn with_per_connection_event_buffer_size(mut self, size: usize) -> Self {
622        self.per_connection_event_buffer_size = size;
623        self
624    }
625
626    pub fn with_idle_connection_timeout(mut self, timeout: Duration) -> Self {
627        self.idle_connection_timeout = timeout;
628        self
629    }
630
631    pub fn with_max_negotiating_inbound_streams(mut self, count: usize) -> Self {
632        self.max_negotiating_inbound_streams = count;
633        self
634    }
635}