1use std::{
2 future::Future,
3 pin::Pin,
4 sync::Arc,
5 task::{Context, Poll},
6 time::Duration,
7};
8
9use web_transport_trait::Stats;
10
11use crate::{
12 Error, Version, bandwidth,
13 util::{MaybeBoxedExt, MaybeSendBox},
14};
15
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
23#[non_exhaustive]
24pub struct ConnectionStats {
25 pub rtt: Option<Duration>,
27
28 pub estimated_send_rate: Option<u64>,
30
31 pub estimated_recv_rate: Option<u64>,
35
36 pub bytes_sent: Option<u64>,
38
39 pub bytes_received: Option<u64>,
41
42 pub bytes_lost: Option<u64>,
44
45 pub packets_sent: Option<u64>,
47
48 pub packets_received: Option<u64>,
50
51 pub packets_lost: Option<u64>,
53}
54
55#[derive(Clone)]
66pub struct Session {
67 shared: Arc<SessionShared>,
68 version: Version,
69 send_bandwidth: Option<bandwidth::Consumer>,
70 recv_bandwidth: Option<bandwidth::Consumer>,
71}
72
73impl Session {
74 pub fn version(&self) -> Version {
76 self.version
77 }
78
79 pub fn send_bandwidth(&self) -> Option<bandwidth::Consumer> {
83 self.send_bandwidth.clone()
84 }
85
86 pub fn recv_bandwidth(&self) -> Option<bandwidth::Consumer> {
90 self.recv_bandwidth.clone()
91 }
92
93 pub fn stats(&self) -> ConnectionStats {
98 let mut stats = self.shared.inner.stats();
99 stats.estimated_recv_rate = self.recv_bandwidth.as_ref().and_then(bandwidth::Consumer::peek);
100 stats
101 }
102
103 pub fn abort(&self, err: Error) {
106 self.shared.close(err.to_code(), err.to_string().as_ref());
107 }
108
109 pub async fn closed(&self) -> Error {
111 Error::Transport(self.shared.inner.closed().await)
112 }
113}
114
115pub struct Driver {
128 state: DriverState,
129 park: kio::Park,
133}
134
135struct DriverState {
137 protocol: MaybeSendBox<'static, Result<(), Error>>,
138 maintenance: Option<MaybeSendBox<'static, ()>>,
143 result: Option<Result<(), Error>>,
145}
146
147impl Driver {
148 pub fn poll(&mut self, waiter: &kio::Waiter) -> Poll<Result<(), Error>> {
153 self.state.poll(waiter)
154 }
155}
156
157impl DriverState {
158 fn poll(&mut self, waiter: &kio::Waiter) -> Poll<Result<(), Error>> {
159 if let Some(result) = &self.result {
160 return Poll::Ready(result.clone());
161 }
162
163 if let Some(maintenance) = &mut self.maintenance
164 && waiter.poll_future(maintenance.as_mut()).is_ready()
165 {
166 self.maintenance = None;
167 }
168
169 let result = std::task::ready!(waiter.poll_future(self.protocol.as_mut()));
170 self.result = Some(result.clone());
171 self.maintenance = None;
174 Poll::Ready(result)
175 }
176}
177
178impl Future for Driver {
179 type Output = Result<(), Error>;
180
181 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
182 let this = &mut *self;
183 let waiter = this.park.hold(cx);
186 this.state.poll(waiter)
187 }
188}
189
190struct SessionShared {
194 inner: Box<dyn SessionInner>,
195 closed: std::sync::atomic::AtomicBool,
196}
197
198impl SessionShared {
199 fn close(&self, code: u32, reason: &str) {
200 if !self.closed.swap(true, std::sync::atomic::Ordering::SeqCst) {
201 self.inner.close(code, reason);
202 }
203 }
204}
205
206impl Drop for SessionShared {
207 fn drop(&mut self) {
208 self.close(Error::Cancel.to_code(), "dropped");
209 }
210}
211
212impl Session {
213 pub(super) fn new<S: web_transport_trait::Session>(
214 session: S,
215 version: Version,
216 recv_bandwidth: Option<bandwidth::Consumer>,
217 protocol: MaybeSendBox<'static, Result<(), Error>>,
218 ) -> (Self, Driver) {
219 let (send_bandwidth, maintenance) = if session.stats().estimated_send_rate().is_some() {
221 let producer = bandwidth::Producer::new();
222 let consumer = producer.consume();
223
224 let mut monitor = SendBandwidth::new(session.clone(), producer);
225 let maintenance = async move { kio::wait(|waiter| monitor.poll(waiter)).await }.maybe_boxed();
226
227 (Some(consumer), Some(maintenance))
228 } else {
229 (None, None)
230 };
231
232 let session = Self {
233 shared: Arc::new(SessionShared {
234 inner: Box::new(session),
235 closed: std::sync::atomic::AtomicBool::new(false),
236 }),
237 version,
238 send_bandwidth,
239 recv_bandwidth,
240 };
241 let driver = Driver {
242 state: DriverState {
243 protocol,
244 maintenance,
245 result: None,
246 },
247 park: kio::Park::default(),
248 };
249
250 (session, driver)
251 }
252}
253
254struct SendBandwidth<S> {
260 session: S,
261 producer: bandwidth::Producer,
262 closed: MaybeSendBox<'static, ()>,
264 mode: SendBandwidthMode,
265}
266
267enum SendBandwidthMode {
268 Idle,
270 Polling { sleep: MaybeSendBox<'static, ()> },
272}
273
274impl<S: web_transport_trait::Session> SendBandwidth<S> {
275 const POLL_INTERVAL: Duration = Duration::from_millis(100);
276
277 fn new(session: S, producer: bandwidth::Producer) -> Self {
278 let closed = {
279 let session = session.clone();
280 async move {
281 session.closed().await;
282 }
283 }
284 .maybe_boxed();
285
286 Self {
287 session,
288 producer,
289 closed,
290 mode: SendBandwidthMode::Idle,
291 }
292 }
293
294 fn sample(&mut self) -> Result<(), Error> {
297 let bitrate = self.session.stats().estimated_send_rate();
298 self.producer.set(bitrate)?;
299 self.mode = SendBandwidthMode::Polling {
300 sleep: web_async::time::sleep(Self::POLL_INTERVAL).maybe_boxed(),
301 };
302 Ok(())
303 }
304
305 fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> {
306 if waiter.poll_future(self.closed.as_mut()).is_ready() {
307 return Poll::Ready(());
308 }
309
310 loop {
311 match &mut self.mode {
312 SendBandwidthMode::Idle => {
313 match self.producer.poll_used(waiter) {
314 Poll::Ready(Ok(())) => {}
316 Poll::Ready(Err(_)) => return Poll::Ready(()),
317 Poll::Pending => return Poll::Pending,
318 }
319 if self.sample().is_err() {
320 return Poll::Ready(());
321 }
322 }
323 SendBandwidthMode::Polling { sleep } => {
324 match self.producer.poll_unused(waiter) {
326 Poll::Ready(Ok(())) => {
327 self.mode = SendBandwidthMode::Idle;
328 continue;
329 }
330 Poll::Ready(Err(_)) => return Poll::Ready(()),
331 Poll::Pending => {}
332 }
333
334 if waiter.poll_future(sleep.as_mut()).is_pending() {
335 return Poll::Pending;
336 }
337 if self.sample().is_err() {
338 return Poll::Ready(());
339 }
340 }
342 }
343 }
344 }
345}
346
347trait SessionInner: web_transport_trait::MaybeSend + web_transport_trait::MaybeSync {
351 fn close(&self, code: u32, reason: &str);
352 fn closed(&self) -> MaybeSendBox<'_, String>;
353 fn stats(&self) -> ConnectionStats;
354}
355
356impl<S: web_transport_trait::Session> SessionInner for S {
357 fn close(&self, code: u32, reason: &str) {
358 S::close(self, code, reason);
359 }
360
361 fn closed(&self) -> MaybeSendBox<'_, String> {
362 Box::pin(async move { S::closed(self).await.to_string() })
363 }
364
365 fn stats(&self) -> ConnectionStats {
366 let stats = S::stats(self);
369 ConnectionStats {
370 rtt: stats.rtt(),
371 estimated_send_rate: stats.estimated_send_rate(),
372 bytes_sent: stats.bytes_sent(),
373 bytes_received: stats.bytes_received(),
374 bytes_lost: stats.bytes_lost(),
375 packets_sent: stats.packets_sent(),
376 packets_received: stats.packets_received(),
377 packets_lost: stats.packets_lost(),
378 ..Default::default()
379 }
380 }
381}