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>>,
146}
147
148impl Driver {
149 pub fn poll(&mut self, waiter: &kio::Waiter) -> Poll<Result<(), Error>> {
154 self.state.poll(waiter)
155 }
156
157 pub(super) async fn wait_ready(&mut self, poll_ready: impl Fn(&kio::Waiter) -> Poll<()>) {
164 kio::wait(|waiter| {
165 if poll_ready(waiter).is_ready() {
166 return Poll::Ready(());
167 }
168 let _ = self.poll(waiter);
169 Poll::Pending
170 })
171 .await
172 }
173}
174
175impl DriverState {
176 fn poll(&mut self, waiter: &kio::Waiter) -> Poll<Result<(), Error>> {
177 if let Some(result) = &self.result {
178 return Poll::Ready(result.clone());
179 }
180
181 if let Some(maintenance) = &mut self.maintenance
182 && waiter.poll_future(maintenance.as_mut()).is_ready()
183 {
184 self.maintenance = None;
185 }
186
187 let result = std::task::ready!(waiter.poll_future(self.protocol.as_mut()));
188 self.result = Some(result.clone());
189 self.maintenance = None;
192 Poll::Ready(result)
193 }
194}
195
196impl Future for Driver {
197 type Output = Result<(), Error>;
198
199 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
200 let this = &mut *self;
201 let waiter = this.park.hold(cx);
204 this.state.poll(waiter)
205 }
206}
207
208struct SessionShared {
212 inner: Box<dyn SessionInner>,
213 closed: std::sync::atomic::AtomicBool,
214}
215
216impl SessionShared {
217 fn close(&self, code: u32, reason: &str) {
218 if !self.closed.swap(true, std::sync::atomic::Ordering::SeqCst) {
219 self.inner.close(code, reason);
220 }
221 }
222}
223
224impl Drop for SessionShared {
225 fn drop(&mut self) {
226 self.close(Error::Cancel.to_code(), "dropped");
227 }
228}
229
230impl Session {
231 pub(super) fn new<S: web_transport_trait::Session>(
232 session: S,
233 version: Version,
234 recv_bandwidth: Option<bandwidth::Consumer>,
235 protocol: MaybeSendBox<'static, Result<(), Error>>,
236 ) -> (Self, Driver) {
237 let (send_bandwidth, maintenance) = if session.stats().estimated_send_rate().is_some() {
239 let producer = bandwidth::Producer::new();
240 let consumer = producer.consume();
241
242 let mut monitor = SendBandwidth::new(session.clone(), producer);
243 let maintenance = async move { kio::wait(|waiter| monitor.poll(waiter)).await }.maybe_boxed();
244
245 (Some(consumer), Some(maintenance))
246 } else {
247 (None, None)
248 };
249
250 let session = Self {
251 shared: Arc::new(SessionShared {
252 inner: Box::new(session),
253 closed: std::sync::atomic::AtomicBool::new(false),
254 }),
255 version,
256 send_bandwidth,
257 recv_bandwidth,
258 };
259 let driver = Driver {
260 state: DriverState {
261 protocol,
262 maintenance,
263 result: None,
264 },
265 park: kio::Park::default(),
266 };
267
268 (session, driver)
269 }
270}
271
272struct SendBandwidth<S> {
278 session: S,
279 producer: bandwidth::Producer,
280 closed: MaybeSendBox<'static, ()>,
282 mode: SendBandwidthMode,
283}
284
285enum SendBandwidthMode {
286 Idle,
288 Polling { sleep: MaybeSendBox<'static, ()> },
290}
291
292impl<S: web_transport_trait::Session> SendBandwidth<S> {
293 const POLL_INTERVAL: Duration = Duration::from_millis(100);
294
295 fn new(session: S, producer: bandwidth::Producer) -> Self {
296 let closed = {
297 let session = session.clone();
298 async move {
299 session.closed().await;
300 }
301 }
302 .maybe_boxed();
303
304 Self {
305 session,
306 producer,
307 closed,
308 mode: SendBandwidthMode::Idle,
309 }
310 }
311
312 fn sample(&mut self) -> Result<(), Error> {
315 let bitrate = self.session.stats().estimated_send_rate();
316 self.producer.set(bitrate)?;
317 self.mode = SendBandwidthMode::Polling {
318 sleep: web_async::time::sleep(Self::POLL_INTERVAL).maybe_boxed(),
319 };
320 Ok(())
321 }
322
323 fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> {
324 if waiter.poll_future(self.closed.as_mut()).is_ready() {
325 return Poll::Ready(());
326 }
327
328 loop {
329 match &mut self.mode {
330 SendBandwidthMode::Idle => {
331 match self.producer.poll_used(waiter) {
332 Poll::Ready(Ok(())) => {}
334 Poll::Ready(Err(_)) => return Poll::Ready(()),
335 Poll::Pending => return Poll::Pending,
336 }
337 if self.sample().is_err() {
338 return Poll::Ready(());
339 }
340 }
341 SendBandwidthMode::Polling { sleep } => {
342 match self.producer.poll_unused(waiter) {
344 Poll::Ready(Ok(())) => {
345 self.mode = SendBandwidthMode::Idle;
346 continue;
347 }
348 Poll::Ready(Err(_)) => return Poll::Ready(()),
349 Poll::Pending => {}
350 }
351
352 if waiter.poll_future(sleep.as_mut()).is_pending() {
353 return Poll::Pending;
354 }
355 if self.sample().is_err() {
356 return Poll::Ready(());
357 }
358 }
360 }
361 }
362 }
363}
364
365trait SessionInner: web_transport_trait::MaybeSend + web_transport_trait::MaybeSync {
369 fn close(&self, code: u32, reason: &str);
370 fn closed(&self) -> MaybeSendBox<'_, String>;
371 fn stats(&self) -> ConnectionStats;
372}
373
374impl<S: web_transport_trait::Session> SessionInner for S {
375 fn close(&self, code: u32, reason: &str) {
376 S::close(self, code, reason);
377 }
378
379 fn closed(&self) -> MaybeSendBox<'_, String> {
380 Box::pin(async move { S::closed(self).await.to_string() })
381 }
382
383 fn stats(&self) -> ConnectionStats {
384 let stats = S::stats(self);
387 ConnectionStats {
388 rtt: stats.rtt(),
389 estimated_send_rate: stats.estimated_send_rate(),
390 bytes_sent: stats.bytes_sent(),
391 bytes_received: stats.bytes_received(),
392 bytes_lost: stats.bytes_lost(),
393 packets_sent: stats.packets_sent(),
394 packets_received: stats.packets_received(),
395 packets_lost: stats.packets_lost(),
396 ..Default::default()
397 }
398 }
399}