1use airio_core::{StreamMuxer, Upgrade, UpgradeInfo, muxing::StreamMuxerEvent};
2use futures::{AsyncRead, AsyncWrite, future, ready};
3use std::{
4 collections::VecDeque,
5 io, iter,
6 pin::Pin,
7 task::{Context, Poll, Waker},
8};
9
10pub use yamux::{Config, Connection, ConnectionError, Mode, Stream};
11
12#[derive(Debug)]
13pub struct Muxer<C> {
14 connection: Connection<C>,
15 inbound_stream_buffer: VecDeque<Stream>,
16 inbound_stream_waker: Option<Waker>,
17}
18
19impl<C> Muxer<C>
20where
21 C: AsyncRead + AsyncWrite + Unpin + 'static,
22{
23 pub fn new(connection: Connection<C>) -> Self {
24 Muxer {
25 connection,
26 inbound_stream_buffer: VecDeque::with_capacity(MAX_BUFFERED_INBOUND_STREAMS),
27 inbound_stream_waker: None,
28 }
29 }
30}
31
32const MAX_BUFFERED_INBOUND_STREAMS: usize = 256;
33
34impl<C> StreamMuxer for Muxer<C>
35where
36 C: AsyncRead + AsyncWrite + Unpin + 'static,
37{
38 type Substream = Stream;
39 type Error = ConnectionError;
40
41 fn poll_inbound(
42 mut self: Pin<&mut Self>,
43 cx: &mut Context<'_>,
44 ) -> Poll<Result<Self::Substream, Self::Error>> {
45 if let Some(stream) = self.inbound_stream_buffer.pop_front() {
46 return Poll::Ready(Ok(stream));
47 }
48 self.inbound_stream_waker = Some(cx.waker().clone());
49 Poll::Pending
50 }
51
52 fn poll_outbound(
53 mut self: Pin<&mut Self>,
54 cx: &mut Context<'_>,
55 ) -> Poll<Result<Self::Substream, Self::Error>> {
56 self.as_mut().connection.poll_new_outbound(cx)
57 }
58
59 fn poll(
60 mut self: Pin<&mut Self>,
61 cx: &mut Context<'_>,
62 ) -> Poll<Result<StreamMuxerEvent, Self::Error>> {
63 let mut this = self.as_mut();
64 let inbound_stream = ready!(this.connection.poll_next_inbound(cx))
65 .ok_or_else(|| ConnectionError::Closed)??;
66
67 if this.inbound_stream_buffer.len() >= MAX_BUFFERED_INBOUND_STREAMS {
68 tracing::warn!(
69 "Inbound stream buffer is full, dropping stream: {}",
70 inbound_stream.id()
71 );
72 drop(inbound_stream);
73 } else {
74 this.inbound_stream_buffer.push_back(inbound_stream);
75 if let Some(waker) = this.inbound_stream_waker.take() {
76 waker.wake();
77 }
78 }
79 cx.waker().wake_by_ref();
81 Poll::Pending
82 }
83
84 #[tracing::instrument(level = "trace", name = "StreamMuxer::poll_close", skip(self, cx))]
85 fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
86 self.as_mut().connection.poll_close(cx)
87 }
88}
89
90#[derive(Debug, Clone)]
91pub struct UpgradeConfig(Config);
92
93impl From<Config> for UpgradeConfig {
94 fn from(config: Config) -> Self {
95 UpgradeConfig(config)
96 }
97}
98
99impl Default for UpgradeConfig {
100 fn default() -> Self {
101 UpgradeConfig(Config::default())
102 }
103}
104
105impl UpgradeInfo for UpgradeConfig {
106 type Info = &'static str;
107 type InfoIter = iter::Once<Self::Info>;
108
109 fn protocol_info(&self) -> Self::InfoIter {
110 iter::once("/v1/yamux")
111 }
112}
113
114impl<C> Upgrade<C> for UpgradeConfig
115where
116 C: AsyncRead + AsyncWrite + Send + Unpin + 'static,
117{
118 type Output = Muxer<C>;
119 type Error = io::Error;
120 type Future = future::Ready<Result<Self::Output, Self::Error>>;
121
122 fn upgrade_inbound(self, socket: C, _: Self::Info) -> Self::Future {
123 let connection = Connection::new(socket, self.0, Mode::Client);
124 future::ready(Ok(Muxer::new(connection)))
125 }
126
127 fn upgrade_outbound(self, socket: C, _: Self::Info) -> Self::Future {
128 let connection = Connection::new(socket, self.0, Mode::Server);
129 future::ready(Ok(Muxer::new(connection)))
130 }
131}